Rust: i tipi primitivi di base

Rust è un linguaggio compilato: il codice sorgente viene analizzato dal compilatore e tradotto in un file binario che, quando eseguito, viene caricato interamente in memoria. Esistono numerosi linguaggio definiti come compilati just-in-time: in breve viene “eseguito” il sorgente che, in tempo reale, viene traslato ed eseguito. Una specie di compilazione al volo, se così possiamo definirla.

Rust è definito anche un linguaggio statically typed, che in italiano credo possa essere tradotto con tipizzato staticamente, che per quanto suoni male riesce a rendere il concetto. In pratica i tipi usati per le variabili (sia semplici che compelsse) viene verificato durante la compilazione, in modo da poter verificare eventuali usi non corretti delle variabili. Per variabili complesse intendo strutture composte o tipi definiti dall’utente. Il compilatore identifica tutti i tipi utilizzati, ma questo non significa che il programmatore debba definirli tutti, sempre, esplicitamente. Infatti esiste il concetto di inferenza di tipo, che avviene quando è possibile dedurre il tipo di variabile utilizzato in base al contesto. Ad esempio, se ho una funzione che mi restituisce una variabile di tipo intero a 16 bit, nella funzione posso dichiarare una variabile senza specificarne il tipo, usarla[¹], e poi ritornarla all’uscita della funzione. Il compilatore può dedurre il tipo usato nella funzione dal fatto che abbiamo esplicitamente indicato il tipo ritornato. Faccio un esempio:

fn crea_numero() -> i16 {
let mut numero = 0;
numero = numero + 10;
return numero;
}

La funzione crea_numero restituisce il valore 10 di tipo intero a 16 bit. Nella dichiarazione della variabile numero non abbiamo indicato il tipo, ma il compilatore è intelligente a sufficienza da capire che, se restiuiamo il tipo i16, allora probabilmente lo stiamo dichiarando proprio di quel tipo.

Per quanto riguarda i tipi offerti da Rust, preferirei non soffermarmi su cosa sia una word, un char, eccetera. Però devo rivordarmi che Rust offere tipi interi di varie dimensioni (iN con N = {16,32,64} per i tipi con segno e uN con N ={16,32,64} per i tipi senza segno) e due variabili generiche che dipendono dalla dimensione di una word sul sistema in uso: usize e isize. Questi due ultimi tipi vengono solitamente usati come variabili per i contatori e nei cicli, con una logica del tipo "conto da zero a ", che può essere 32 bit o 64 bit in base all'architettura usata[^2]. I tipi in virgola mobile sono f32e f64, classici e visti in molti altri linguaggi. Vi è un tipo specifico per le variabili booleane (bool) ed uno per i singoli caratteri (char). I tipi più complessi preferisco affrontarli con calma dopo, non ha senso introdurli ora come mera lista senza senso.

Controllo dimensionale

Da notare il fatto che il tipo usize sembra essere obbligatorio per le variabili che contengono gli indici degli array. Inoltre, poiché ogni tipo ha una cifra massima che può contenere (e che dipende dal numero di byte che utilizza per essere rappresentato in memoria), Rust è capace di effettuare il controllo dell' overflow durante la compilazione di Debug.

Calma.

Per prima cosa questo controllo di overflow consiste nel verificare che non si cerchi di inserire in una variabile un numero più grande del massimo numero possibile. Seconda cosa, la compilazione Debug indica (non vorrei sbagliarmi) quella effettuata durante la compilazione con cargo usando Debug come opzione. Consiste, senza entrare nei dettagli, in un tipo di compilazione in cui eventuali warning normalmente disattivati vengono utilizzati, insieme ad espliciti controlli sul codice sorgente. A quanto dice il manuale, durante la compilazione di Debug viene effettuato questo controllo deglio overflow, mentre nella compilazione normale (Release Build) Rust accetta, ad esempio, incrementi numerici superiori al valore massimo, trattandoli come overflow controllati. Definirei un overflow come controllato, quando sfrutto il limite dei bit per passare dal valore massimo al valore minimo accettato da una variabile. Questo concetto in realtà è un qualcosa di non utile ai fini del linguaggio, ma un trucco di solito usato dagli informatici che sfrutta il fatto che ogni variabile, per quanto grande possa essere, viene immagazzinata in un numero definito di bit. Se si incrementa quella variabile oltre il suo valore massimo, il nuovo valore “ricomincerà” dal valore minimo consentito, come se si tornasse a casa dopo aver circumnavigato il globo. Direi che questa parte dell’overflow controllato può essere accantonato per il momento, poiché di dubbia utilità (leggi nessuna) per capire come programmare.

Tipo di default ed altre cose che non serve sapere ora

Rust, come abbiamo detto, cerca di determinare il tipo in base a come viene utilizzata la variabile. In realtà quando più possibilità sono compatibili all’uso di quella variabile, Rust usa (se possibile) il tipo i32 come tipo di default. Se ci riusciamo, però, credo sia sempre meglio non affidarsi così tanto al compilatore e gestire da noi in modo univoco il tipo.

Vorrei continuare questa disamina raccontanto il tipo char, o i literals usati per rendere le variabili più leggibili, ma sono tutte cose non mandatory per la comprensione del testo. Magari poi ci tornerò. Potrei fornire una rapida panoramica di questi dettagli, ma boh alla fine sticazzi non è importante e se proprio non sai di cosa parlo puoi sempre aprire Google.

Un dettaglio che reputo importante è che per il tipo bool, Rust usa un intero byte a differenza di molti altri linguaggi. Questo rende il tipo booleano un tipo degno di rispetto :-D tanto quanto le altre variabili, e che quindi può essere anche il destinatario di un puntatore. Per ora magari sembra una cosa oscura, ma avendo dimistichezza con altri linguaggi, questo è un piccolo dettaglio che è comodo avere.

[¹]: compatibilimente al tipo intero a 16 bit 
[²]: non credo esistano sistemi operativi a 16 bit ancora in circolazione, e se esistono non credo vi sia il relativo compilatore Rust, almeno spero!

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.