Scope delle Variabili in Go
Lo scope (ambito di visibilità ) di una variabile in Go determina dove quella variabile è accessibile nel codice. Comprendere lo scope è fondamentale per scrivere codice corretto e prevedibile.
Scope a Livello di Pacchetto
Le variabili dichiarate fuori da qualsiasi funzione sono accessibili in tutto il pacchetto:
package main
var contatore int = 0 // Visibile in tutto il pacchetto
func incrementa() {
contatore++ // Accede alla variabile di pacchetto
}
func main() {
incrementa()
fmt.Println(contatore) // 1
}
Se il nome inizia con lettera maiuscola, la variabile è esportata e accessibile anche da altri pacchetti.
Scope a Livello di Funzione
Le variabili dichiarate all’interno di una funzione sono visibili solo in quella funzione:
func main() {
messaggio := "Ciao"
fmt.Println(messaggio) // OK
}
func altraFunzione() {
// fmt.Println(messaggio) // ERRORE: messaggio non è definita qui
}
Scope a Livello di Blocco
Ogni blocco {} crea un nuovo scope. Le variabili dichiarate in un blocco non sono visibili al di fuori:
func main() {
x := 10
if x > 5 {
y := 20 // y è visibile solo in questo blocco if
fmt.Println(x, y) // 10 20
}
// fmt.Println(y) // ERRORE: y non è definita qui
for i := 0; i < 3; i++ {
// i è visibile solo nel ciclo for
fmt.Println(i)
}
// fmt.Println(i) // ERRORE: i non è definita qui
}
Scope con If e Inizializzazione
L’inizializzazione nell’if crea una variabile visibile solo nel blocco if-else:
if valore, err := strconv.Atoi("42"); err == nil {
fmt.Println(valore) // 42 - visibile qui
} else {
fmt.Println(err) // valore ed err visibili anche nell'else
}
// valore e err NON sono visibili qui
Shadowing (Oscuramento)
Una variabile in uno scope interno può “oscurare” una variabile con lo stesso nome in uno scope esterno:
func main() {
x := 10
fmt.Println(x) // 10
{
x := 20 // Nuova variabile x, oscura quella esterna
fmt.Println(x) // 20
}
fmt.Println(x) // 10 - la x esterna non è cambiata
}
Attenzione: lo shadowing con := è una fonte comune di bug:
func main() {
err := errors.New("errore iniziale")
if true {
// Crea una NUOVA variabile err, non modifica quella esterna
valore, err := qualcosa()
fmt.Println(valore, err)
}
fmt.Println(err) // Ancora "errore iniziale"!
}
Best Practice
- Dichiara le variabili il piĂą vicino possibile al loro utilizzo
- Fai attenzione allo shadowing involontario con
:= - Limita lo scope delle variabili al minimo necessario
- Usa nomi diversi se hai bisogno di accedere a variabili di scope diversi
Conclusione
Go utilizza lo scope lessicale con blocchi annidati. Ogni {} crea un nuovo scope, e le variabili sono visibili solo nel blocco in cui sono dichiarate e nei blocchi interni. Lo shadowing è una caratteristica potente ma può causare bug sottili se non gestita con attenzione.