Menu

Tipi primitivi in Zero: interi, float, bool, String e Void

I tipi integrati che Zero ti offre fin da subito: interi con e senza segno di ogni ampiezza, float, booleani, caratteri, stringhe e il tipo vuoto Void.

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.

FamigliaTipiNote
Interi con segnoi8, i16, i32, i64Complemento a due.
Interi senza segnou8, u16, u32, u64Solo 0 e positivi.
Ampiezza di puntatoreusize, isizeL'ampiezza corrisponde al puntatore della piattaforma.
Floatf32, f64IEEE-754.
Booleanobooltrue o false.
CaratterecharUn singolo scalare Unicode.
StringaStringStringa UTF-8.
VuotoVoid"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:

  • i32 per la maggior parte dei calcoli con segno. Abbastanza ampio per quasi tutto ciò che conteresti, veloce su ogni piattaforma.
  • u8 per il lavoro a livello di byte. Byte da un file, byte in un buffer, byte in rete.
  • u32 / u64 per conteggi non negativi quando l'intervallo conta. Offset di file oltre i 2 GB, conteggi grandi.
  • usize per dimensioni e indici. Ha l'ampiezza di un puntatore: corrisponde a ciò che la piattaforma usa per indirizzare la memoria.
  • i64 per 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

SuffissoTipoEsempio
_i8 / _i16 / _i32 / _i64Intero con segno127_i8
_u8 / _u16 / _u32 / _u64Intero senza segno255_u8
_usize / _isizeAmpiezza di puntatore0_usize
_f32 / _f64Float0.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.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA