I tipi integrati
Zero ti offre un insieme piccolo e regolare di tipi primitivi. Niente di esotico, niente di sorprendente: solo quelli che servono a ogni linguaggio di sistema, con nomi coerenti.
| Famiglia | Tipi | Note |
|---|---|---|
| Interi con segno | i8, i16, i32, i64 | Complemento a due. |
| Interi senza segno | u8, u16, u32, u64 | Solo 0 e positivi. |
| Ampiezza di puntatore | usize, isize | L'ampiezza corrisponde al puntatore della piattaforma. |
| Float | f32, f64 | IEEE-754. |
| Booleano | bool | true o false. |
| Carattere | char | Un singolo scalare Unicode. |
| Stringa | String | Stringa UTF-8. |
| Vuoto | Void | "Nessun valore utile." |
Questo è l'elenco completo dei primitivi che userai ogni giorno. I tipi composti, cioè shape, enum e choice, si costruiscono a partire da questi.
Interi
I tipi interi seguono uno schema di nomi uniforme: i per quelli con segno, u per quelli senza segno, seguiti dall'ampiezza in bit. Quindi i32 è un intero con segno a 32 bit; u8 è un byte senza segno; i64 è un intero con segno a 64 bit.
let small_signed: i8 = -120
let byte: u8 = 250
let id: i32 = 1
let big: i64 = 9_000_000_000
let index: usize = 0
Il tipo predefinito per un letterale senza suffisso è i32, a meno che il contesto non imponga qualcos'altro:
let answer = 42 // i32
Quando ti serve un'ampiezza specifica, aggiungi un suffisso al letterale o annota il binding:
let byte = 250_u8 // letterale tipizzato
let byte: u8 = 250 // binding tipizzato
Entrambe le forme producono lo stesso valore. La forma con suffisso sul letterale è comoda quando passi un letterale direttamente a una funzione o costruisci una struttura:
let pair: BytePair = Pair { left: 1_u8, right: 2_u8 }
Quale ampiezza scegliere
Una breve regola pratica:
i32per la maggior parte dei calcoli con segno. Abbastanza ampio per quasi tutto ciò che conteresti, veloce su ogni piattaforma.u8per il lavoro a livello di byte. Byte da un file, byte in un buffer, byte in rete.u32/u64per conteggi non negativi quando l'intervallo conta. Offset di file oltre i 2 GB, conteggi grandi.usizeper dimensioni e indici. Ha l'ampiezza di un puntatore: corrisponde a ciò che la piattaforma usa per indirizzare la memoria.i64per il tempo trascorso dall'epoch e simili. Abbastanza grande per i nanosecondi di centinaia di anni.
Scegliere il tipo più piccolo che basta è una buona pratica; scegliere un tipo troppo piccolo e andare in overflow è un problema molto più grave che scegliere un bit di troppo.
Booleani
let ok = true
let done: bool = false
bool ha esattamente due valori: true e false. Sono letterali, non costanti da importare da qualche parte. La condizione di un if o di un while è un bool: non esiste truthiness implicita per interi o stringhe.
if ok {
check world.out.write("sì\n")
} else {
check world.out.write("no\n")
}
If/else tratta le condizioni nel dettaglio.
Float
f32 e f64 sono rispettivamente numeri in virgola mobile IEEE-754 a 32 e 64 bit. Usali quando ti servono valori frazionari: misure, rapporti, geometria. Per l'aritmetica esatta sulle valute, preferisci interi nell'unità più piccola (centesimi, satoshi) ai float.
let ratio: f32 = 0.5
let pi: f64 = 3.141592653589793
f64 è il tipo predefinito per i letterali float senza suffisso.
Caratteri e stringhe
Un char contiene un singolo valore scalare Unicode:
let initial: char = 'Z'
Una String è una sequenza di caratteri, di solito codificata in UTF-8 dalla libreria standard. I letterali stringa usano le virgolette doppie:
let message: String = "ciao da zero\n"
Le sequenze di escape che ti aspetti funzionano: \n per andare a capo, \t per la tabulazione, \\ per una barra rovesciata letterale, \" per delle virgolette doppie letterali.
let multi_line = "riga uno\nriga due\n"
La libreria standard offre viste a livello di byte su una stringa per il lavoro a basso livello. La forma std.mem.span("zero") restituisce uno Span<u8> sui byte: utile quando analizzi, calcoli un hash o confronti byte per byte.
Void
Void è il tipo di Zero per "nessun valore di ritorno utile". Lo usano le funzioni che esistono per i loro effetti collaterali:
pub fun main(world: World) -> Void raises {
check world.out.write("ciao\n")
}
main scrive qualcosa e termina. Non c'è nessun valore da restituire, quindi il tipo è Void. Vedrai Void sulla maggior parte delle funzioni che toccano World: le usi per il loro effetto, non per il loro risultato.
Trattini bassi nei letterali numerici
I letterali numerici lunghi possono usare trattini bassi come separatori visivi. Il compilatore li ignora, quindi servono solo alla leggibilità:
let big = 9_000_000_000_i64
let bytes = 1_048_576_u32 // 1 MiB
Mettili ovunque le cifre diventino difficili da contare.
Promemoria dei suffissi per letterali tipizzati
| Suffisso | Tipo | Esempio |
|---|---|---|
_i8 / _i16 / _i32 / _i64 | Intero con segno | 127_i8 |
_u8 / _u16 / _u32 / _u64 | Intero senza segno | 255_u8 |
_usize / _isize | Ampiezza di puntatore | 0_usize |
_f32 / _f64 | Float | 0.5_f32 |
Usali quando costruisci un valore in un contesto che non fissa il tipo.
Prossimo passo: funzioni
I primitivi non servono a nulla senza qualcosa da farci. La prossima pagina tratta le funzioni in Zero: come dichiararle, come restituire valori e come combinarle per costruire programmi reali.
Domande frequenti
Quali tipi primitivi ha Zero?
Zero include gli interi con segno di dimensione fissa i8, i16, i32, i64; gli interi senza segno u8, u16, u32, u64; gli interi con ampiezza di puntatore usize e isize; i float f32 e f64; bool; char; String; e Void per le funzioni che non restituiscono nulla di utile.
Qual è il tipo intero predefinito in Zero?
Un letterale intero senza suffisso come 42 è i32 per impostazione predefinita, a meno che il contesto non imponga un tipo diverso. Per usare un'ampiezza specifica, scrivi il letterale con un suffisso come 42_u8 o 42_i64, oppure annota esplicitamente il tipo del binding con let count: u8 = 42.
Zero ha un tipo stringa separato?
Sì. I letterali stringa come "ciao" hanno un tipo stringa integrato che la libreria standard tratta come una sequenza di byte (spesso UTF-8). Per il lavoro a basso livello sui byte, la libreria standard offre span e utilità a livello di byte; per le operazioni sui singoli caratteri c'è char, che rappresenta un singolo valore scalare.
Cosa significa Void in Zero?
Void è il tipo di ritorno di una funzione che non produce un valore utile: esiste solo per i suoi effetti collaterali. La firma convenzionale pub fun main(world: World) -> Void raises usa Void perché main esiste per fare I/O e terminare, non per produrre un valore.
Qual è la differenza tra i32 e u32 in Zero?
i32 è un intero con segno a 32 bit con intervallo da −2.147.483.648 a 2.147.483.647. u32 è senza segno e ha intervallo da 0 a 4.294.967.295. Usa i tipi con segno quando i valori negativi hanno senso, quelli senza segno quando un valore negativo sarebbe un bug: per conteggi, indici, dimensioni e così via.