È uscito il Corso SQL Completo

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.