Costanti
Cosa sono le costanti?
Le costanti sono valori che non possono essere modificati dopo la loro dichiarazione. In Go, le costanti vengono definite con la parola chiave const e il loro valore deve essere noto al momento della compilazione.
package main
import "fmt"
const pi = 3.14159265358979
func main() {
fmt.Println("Il valore di pi greco e:", pi)
// pi = 3.14 // ERRORE: cannot assign to pi
}
Dichiarazione con const
Le costanti si dichiarano in modo simile alle variabili, ma con const al posto di var:
const nome string = "Go"
const versione = 1.23
const attivo = true
A differenza delle variabili, le costanti non possono essere dichiarate con :=:
// ERRORE: la sintassi breve non e disponibile per le costanti
// pi := 3.14 // questo dichiara una variabile, non una costante
Le costanti possono essere dichiarate sia a livello di pacchetto che all’interno di funzioni:
package main
import "fmt"
const messaggioGlobale = "Ciao dal livello pacchetto"
func main() {
const messaggioLocale = "Ciao dal livello funzione"
fmt.Println(messaggioGlobale)
fmt.Println(messaggioLocale)
}
Costanti tipizzate e non tipizzate
Una delle caratteristiche piu potenti delle costanti in Go e la distinzione tra costanti tipizzate e non tipizzate.
Costanti tipizzate
Una costante tipizzata ha un tipo esplicito e si comporta esattamente come un valore di quel tipo:
const eta int = 30
const altezza float64 = 1.75
const nome string = "Mario"
Costanti non tipizzate
Una costante non tipizzata non ha un tipo fisso e puo essere usata in contesti diversi. Il tipo viene determinato dal contesto in cui la costante viene utilizzata:
const x = 42 // costante non tipizzata
func main() {
var a int = x // x diventa int
var b float64 = x // x diventa float64
var c int64 = x // x diventa int64
fmt.Println(a, b, c) // 42 42 42
}
Questo comportamento e particolarmente utile per le costanti numeriche che devono essere flessibili:
const fattore = 1000
func main() {
var piccolo int16 = fattore // OK
var grande int64 = fattore // OK
var decimale float64 = fattore // OK: diventa 1000.0
fmt.Println(piccolo, grande, decimale)
}
Blocchi di costanti
Puoi raggruppare piu costanti in un blocco per migliorare la leggibilita:
const (
linguaggio = "Go"
versione = "1.23"
autore = "Google"
)
const (
secondiAlMinuto = 60
minutiAllOra = 60
oreAlGiorno = 24
secondiAlGiorno = secondiAlMinuto * minutiAllOra * oreAlGiorno
)
Le costanti in un blocco possono fare riferimento a costanti precedenti e utilizzare espressioni:
package main
import "fmt"
const (
kb = 1024
mb = kb * 1024
gb = mb * 1024
tb = gb * 1024
)
func main() {
fmt.Printf("1 KB = %d byte\n", kb)
fmt.Printf("1 MB = %d byte\n", mb)
fmt.Printf("1 GB = %d byte\n", gb)
fmt.Printf("1 TB = %d byte\n", tb)
}
L’enumeratore iota
iota e un identificatore speciale di Go usato all’interno dei blocchi const per generare una sequenza di valori incrementali. Parte da 0 e si incrementa di 1 per ogni riga nel blocco:
package main
import "fmt"
const (
Lunedi = iota // 0
Martedi // 1
Mercoledi // 2
Giovedi // 3
Venerdi // 4
Sabato // 5
Domenica // 6
)
func main() {
fmt.Println("Lunedi:", Lunedi) // 0
fmt.Println("Venerdi:", Venerdi) // 4
fmt.Println("Domenica:", Domenica) // 6
}
iota con espressioni
Puoi combinare iota con espressioni per creare sequenze personalizzate:
const (
_ = iota // ignora il primo valore (0)
KB = 1 << (10 * iota) // 1 << 10 = 1024
MB // 1 << 20 = 1048576
GB // 1 << 30 = 1073741824
TB // 1 << 40
)
iota per bitmask
iota e molto utile per creare bitmask (maschere di bit):
package main
import "fmt"
const (
Lettura = 1 << iota // 1 (001)
Scrittura // 2 (010)
Esecuzione // 4 (100)
)
func main() {
// Combina i permessi con OR bitwise
permessi := Lettura | Scrittura
fmt.Printf("Permessi: %03b\n", permessi) // 011
// Verifica un permesso con AND bitwise
puoLeggere := permessi&Lettura != 0
puoEseguire := permessi&Esecuzione != 0
fmt.Println("Puo leggere:", puoLeggere) // true
fmt.Println("Puo eseguire:", puoEseguire) // false
}
iota si resetta in ogni blocco const
Ogni nuovo blocco const resetta iota a 0:
const (
A = iota // 0
B // 1
)
const (
C = iota // 0 (resettato)
D // 1
)
Espressioni costanti
Le costanti in Go supportano espressioni che vengono valutate a tempo di compilazione:
package main
import "fmt"
const (
base = 10
doppio = base * 2
triplo = base * 3
quadro = base * base
)
const messaggio = "Go e " + "fantastico!"
func main() {
fmt.Println(doppio) // 20
fmt.Println(triplo) // 30
fmt.Println(quadro) // 100
fmt.Println(messaggio) // Go e fantastico!
}
Le espressioni costanti possono utilizzare operatori aritmetici, di confronto, logici e la concatenazione di stringhe, ma non possono chiamare funzioni (tranne le funzioni built-in len, cap, real, imag e complex su argomenti costanti).
const lunghezza = len("ciao") // OK: len su una costante stringa
// const risultato = math.Sqrt(4) // ERRORE: non e un'espressione costante
Conclusione
Le costanti in Go garantiscono immutabilita e sicurezza nel codice. La distinzione tra costanti tipizzate e non tipizzate offre flessibilita, mentre iota fornisce un meccanismo elegante per creare enumerazioni e sequenze di valori. Le espressioni costanti, valutate a tempo di compilazione, permettono di definire valori derivati senza alcun costo a runtime.