I tipi base di Go sono numeri, booleani e stringhe. Ogni variabile ha esattamente un tipo, fissato in fase di compilazione, e Go non converte mai i tipi al posto tuo. %T stampa il tipo di qualsiasi valore:
Nota che 'G' viene stampato come 71 con tipo int32: un carattere tra apici singoli è una rune, cioè un numero (il code point Unicode). rune è un alias di int32 (lo stesso tipo con un secondo nome), quindi %T riporta int32. Allo stesso modo byte riporta uint8.
Interi
| Tipo | Dimensione | Intervallo |
|---|---|---|
int8 | 8 bit | da -128 a 127 |
int16 | 16 bit | da -32.768 a 32.767 |
int32 | 32 bit | da circa -2,1 miliardi a 2,1 miliardi |
int64 | 64 bit | da circa -9,2 trilioni a 9,2 trilioni |
uint8 (byte) | 8 bit | da 0 a 255 |
uint16 | 16 bit | da 0 a 65.535 |
uint32 | 32 bit | da 0 a circa 4,3 miliardi |
uint64 | 64 bit | da 0 a circa 18,4 trilioni |
int, uint | 32 o 64 bit | dimensione della parola della piattaforma |
uintptr | dimensione della piattaforma | contiene il valore di un puntatore, per il codice a basso livello |
Usa int come scelta predefinita. len() restituisce int, gli indici degli slice sono int e i contatori dei cicli sono int. Su ogni piattaforma a 64 bit int è a 64 bit. Ricorri ai tipi con dimensione quando la dimensione fa parte di un contratto: int32 in un formato di file binario, uint8 per i byte grezzi, int64 per un timestamp Unix in nanosecondi.
Evita i tipi senza segno per quantità che "non possono essere negative", come i conteggi. Sottrarre oltre lo zero fa ricominciare da un numero enorme invece di produrre un valore negativo che potresti intercettare.
Limiti e overflow
Il package math ha una costante per ogni limite. Durante l'esecuzione, un'operazione aritmetica intera che va in overflow ricomincia silenziosamente dall'altro estremo:
Nessun panic, nessun errore: 127 + 1 diventa -128. Solo le espressioni costanti vengono controllate in fase di compilazione (var b int8 = 128 non compila). Se nei tuoi dati è possibile un overflow, controlla prima dell'operazione oppure usa math/big.
Letterali interi
million := 1_000_000 // underscores for readability (Go 1.13+)
mask := 0xFF // hexadecimal
perm := 0o755 // octal (also the older form 0755)
flags := 0b1010 // binary
Numeri in virgola mobile
| Tipo | Dimensione | Precisione |
|---|---|---|
float32 | 32 bit | da circa 6 a 9 cifre significative |
float64 | 64 bit | da circa 15 a 17 cifre significative |
Un letterale con punto decimale o esponente (2.5, 1e6) è float64 per impostazione predefinita, e il package math riceve e restituisce float64. Usalo, a meno che non conti la memoria in un array grande.
I float sono binari, quindi la maggior parte delle frazioni decimali sono approssimazioni:
Ne seguono due regole. Non confrontare mai i float con == dopo dei calcoli. E non memorizzare mai denaro in un float: usa un numero intero di centesimi o una libreria decimale.
Dividere un float per zero dà +Inf, -Inf o NaN invece di provocare un panic. Dividere un intero per zero provoca un panic durante l'esecuzione (runtime error: integer divide by zero), e un divisore zero costante è un errore di compilazione.
Booleani
bool contiene true o false, e il suo valore zero è false. Go non tratta numeri, stringhe vuote o nil come booleani. if count {} è un errore di compilazione; scrivi if count > 0 {}. Gli operatori sono &&, || e !, e && e || sono valutati in cortocircuito.
Stringhe
Una string è una sequenza immutabile di byte, di solito testo UTF-8. len(s) conta i byte, non i caratteri:
é occupa due byte in UTF-8, quindi len riporta 6 per cinque caratteri. Le stringhe tra virgolette doppie elaborano le sequenze di escape come \n; le stringhe grezze tra backtick no, e possono occupare più righe. La pagina sulle stringhe tratta il package strings, e quella su rune e byte approfondisce UTF-8.
byte e rune
| Alias | Uguale a | Contiene |
|---|---|---|
byte | uint8 | un byte di dati grezzi |
rune | int32 | un code point Unicode |
Sono alias, non tipi nuovi: un byte e un uint8 sono intercambiabili senza conversione. I nomi dicono cosa significa il numero.
Numeri complessi
Go ha tipi complessi integrati, complex64 e complex128, con real, imag e il package math/cmplx:
Servono a pochi programmi, ma l'elaborazione dei segnali e un po' di codice numerico li usano.
Tipi composti e di riferimento
I tipi base si combinano in tipi composti. Ognuno ha la sua pagina:
| Tipo | Esempio | Valore zero |
|---|---|---|
| array | [3]int | tre zeri |
| slice | []int | nil |
| map | map[string]int | nil |
| struct | struct{ X, Y int } | ogni campo a zero |
| puntatore | *int | nil |
| funzione | func(int) int | nil |
| channel | chan int | nil |
| interfaccia | error, any | nil |
any è un alias di interface{} (da Go 1.18) e può contenere un valore di qualsiasi tipo.
Tipi con nome
Puoi definire un nuovo tipo a partire da uno esistente. Ha la stessa rappresentazione ma è un tipo distinto, e può avere dei metodi:
type Celsius float64
type UserID int64
var t Celsius = 21.5
var f float64 = t // compile error: cannot use t (variable of float64 type Celsius) as float64 value in variable declaration
Questa rigidità è proprio lo scopo: un UserID non può essere passato per sbaglio dove è atteso un OrderID. Converti esplicitamente quando è ciò che intendi: float64(t). Consulta la conversione di tipo per le regole e le funzioni di strconv per passare tra numeri e stringhe.
Valori zero
Ogni tipo ha un valore zero, cioè ciò che contiene una variabile prima che tu le assegni qualcosa: 0 per i numeri, false per bool, "" per le stringhe e nil per puntatori, slice, mappe, channel, funzioni e interfacce. In Go non esistono variabili non inizializzate.
Domande frequenti
Quanto è grande un int in Go?
int e uint sono a 64 bit sulle piattaforme a 64 bit (amd64, arm64) e a 32 bit sulle piattaforme a 32 bit. Se ti serve una dimensione fissa, per un formato di file o un protocollo di rete, usa int32, int64, uint8 e così via. Per normali contatori, indici e lunghezze, usa int.
Come stampo il tipo di una variabile in Go?
Usa il verbo %T: fmt.Printf("%T\n", x) stampa int, float64, []string, main.User e così via. Nel codice, reflect.TypeOf(x) restituisce la stessa informazione come valore che puoi esaminare.
Qual è la differenza tra byte e rune in Go?
byte è un alias di uint8 e contiene un byte di dati grezzi. rune è un alias di int32 e contiene un code point Unicode. Una stringa è una sequenza di byte; scorrerla con for range la decodifica in rune.
Devo usare float32 o float64 in Go?
Usa float64, a meno che tu non abbia un motivo per fare diversamente. È il tipo predefinito dei letterali in virgola mobile, il tipo con cui lavora il package math e ha una precisione di circa 15-17 cifre decimali significative, contro le 6-9 circa di float32. Scegli float32 solo per dimezzare la memoria in array grandi o per rispettare un formato esterno.
Qual è il valore massimo di int in Go?
Usa le costanti del package math: math.MaxInt (9223372036854775807 sulle piattaforme a 64 bit), math.MinInt, math.MaxInt64, math.MaxUint32 e così via. Le operazioni aritmetiche che superano il limite ricominciano silenziosamente dall'altro estremo durante l'esecuzione; non provocano un panic.