Menu

Costanti in Golang: const tipizzate e non tipizzate

Come funziona const in Go: dichiarare costanti, la differenza tra costanti tipizzate e non tipizzate, le espressioni costanti con precisione arbitraria e perché Go non ha slice, mappe o struct costanti.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

Una costante è un valore fissato in fase di compilazione. La dichiari con const, e Go rifiuta qualsiasi tentativo di modificarla.

Le costanti si possono dichiarare a livello di package o dentro una funzione, una per riga o raggruppate in un blocco const ( ... ). MB e GB sono calcolate a partire da altre costanti, e il compilatore esegue quei calcoli una volta sola, durante la build.

Assegnare un valore a una costante, per esempio MaxRetries = 5, è un errore di compilazione:

./main.go:8:2: cannot assign to MaxRetries (neither addressable nor a map index expression)

Cosa può essere una costante

Solo tre tipi di valori: booleani, numeri (interi, float, numeri complessi e rune) e stringhe. Il valore deve essere calcolabile dal compilatore, quindi letterali, altre costanti, operazioni aritmetiche su di esse e alcune funzioni integrate come len di una stringa costante.

Tutto ciò che richiede di eseguire codice o allocare memoria è escluso:

const Colors = []string{"red", "green"} // slice
const Started = time.Now()              // function call
./main.go:9:16: []string{…} (value of type []string) is not constant
./main.go:10:13: time.Now() (value of struct type time.Time) is not constant

Perché Go non ha slice o mappe costanti

Gli slice, le mappe e le struct che li contengono sono riferimenti a memoria che esiste durante l'esecuzione, quindi il compilatore non può incorporarli nel programma come valori fissi, e Go non ha un modificatore readonly o final per le variabili. Le soluzioni alternative più comuni:

La copia costa un'allocazione a ogni chiamata, il che va bene per dati delle dimensioni di una configurazione. Per le ricerche per chiave, uno switch in una funzione è un'altra opzione simile a una costante: func statusText(code int) string { switch code { ... } }.

Costanti non tipizzate

Una costante dichiarata senza tipo è non tipizzata. Ha una categoria (intero, float, rune, stringa, bool) ma nessun tipo Go specifico finché non viene usata, e si adatta al contesto:

Ratio funziona come int, float64, uint8 e float32 senza conversioni. Per questo time.Sleep(2 * time.Second) compila: 2 è non tipizzato e diventa un time.Duration.

Quando il contesto non richiede un tipo, come in x := Ratio, la costante riceve il suo tipo predefinito:

Categoria di costante non tipizzataTipo predefinito
intero (42)int
virgola mobile (4.2)float64
rune ('a')rune (int32)
complesso (2i)complex128
stringastring
booleanobool

Aritmetica esatta

Le costanti numeriche non tipizzate sono esatte. Il compilatore rappresenta gli interi con almeno 256 bit, quindi i valori intermedi possono essere molto più grandi di qualsiasi tipo Go:

Huge in sé non si può stampare come intero, perché passarla a fmt.Println la converte in int, e il compilatore se ne accorge (float64(Huge) funziona, perché un float può contenere quell'ordine di grandezza):

cannot use Huge (untyped int constant 1267650600228229401496703205376) as int value in argument to fmt.Println (overflows)

Lo stesso controllo blocca errori più piccoli in fase di compilazione, come var b byte = 300:

cannot use 300 (untyped int constant) as byte value in variable declaration (overflows)

Costanti tipizzate

Dai un tipo a una costante e si comporterà ovunque come un valore di quel tipo, compreso il rifiuto di Go di mescolare tipi diversi:

const Limit int = 10

var f float64 = 2
fmt.Println(Limit * f)
invalid operation: Limit * f (mismatched types int and float64)

Con const Limit = 10 (non tipizzata), Limit * f compila e dà 20. Quindi lascia le costanti non tipizzate, a meno che il tipo non abbia un significato. Ce l'ha quando dichiari costanti di un tuo tipo con nome, che è il modo in cui Go costruisce gli enum:

type Weekday int

const (
	Sunday Weekday = iota
	Monday
	Tuesday
)

Qui il tipo è proprio il punto: una funzione che accetta un Weekday documenta cosa vuole. iota e gli schemi di enum basati su di esso sono trattati nella pagina su enum e iota.

const e var a confronto

constvar
Può cambiarenosì
Valore notoin fase di compilazionein fase di esecuzione
Tipi consentitibool, numerici, stringqualsiasi
Occupa memoria durante l'esecuzionenosì
Se ne può prendere l'indirizzo (&x)nosì
Se inutilizzata è un errorenosì, per le locali

Usa const per tutto ciò che è davvero fisso: limiti, dimensioni, nomi, codici di protocollo, stringhe di formato. Ottieni gratis i controlli di overflow in fase di compilazione e l'aritmetica esatta.

Insidie

Le costanti tipizzate non si adattano. const Timeout int = 5 non si può passare dove è atteso un time.Duration senza una conversione; una const Timeout = 5 non tipizzata si può moltiplicare: Timeout * time.Second.

Sulle costanti intere la divisione è intera. const Half = 1 / 2 vale 0, perché entrambi gli operandi sono interi non tipizzati. Scrivi 1.0 / 2 per ottenere 0.5.

Nessun indirizzo. &MaxRetries non compila. Se un'API vuole un *int, copia prima la costante in una variabile.

Domande frequenti

Come si dichiara una costante in Go?

Con const: const MaxRetries = 3 oppure, con un tipo esplicito, const Timeout time.Duration = 5 * time.Second. Raggruppane più di una in un blocco: const ( A = 1; B = 2 ). Il valore deve essere calcolabile in fase di compilazione.

Posso creare uno slice, una mappa o un array costante in Go?

No. Le costanti possono essere solo booleani, numeri (rune comprese) e stringhe. const Colors = []string{"red"} fallisce con is not constant. Usa una var a livello di package e, se chi la usa non deve modificarla, esponi una funzione che restituisce una copia nuova.

Cos'è una costante non tipizzata in Go?

Una costante dichiarata senza tipo, come const Pi = 3.14159. Non ha un tipo fisso finché non viene usata, quindi la stessa costante funziona come float32, come float64 o, se il valore lo permette, come int. Le costanti non tipizzate sono anche esatte: il compilatore mantiene almeno 256 bit di precisione, quindi const Big = 1 << 100 è valida purché tu la usi solo in espressioni i cui risultati ci stanno.

Qual è la differenza tra const e var in Go?

Una const è fissata in fase di compilazione e non può mai cambiare; non occupa memoria durante l'esecuzione e può contenere solo un bool, un numero o una stringa. Una var è una posizione di memoria che può essere riassegnata e può contenere qualsiasi tipo, compresi valori calcolati durante l'esecuzione come time.Now().

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA