En Go, las reglas del ámbito de visibilidad de las variables (scoping) están estrictamente definidas por bloques ({}), y el nombre de una variable puede ser oscurecido (shadowing) en ámbitos anidados. Especialmente, surgen muchas trampas en funciones anidadas, funciones anónimas, bucles y al declarar variables con el mismo nombre en diferentes niveles.
Go ha minimizado intencionadamente el comportamiento "mágico" del ámbito de visibilidad para hacer el código más legible. Sin embargo, la flexibilidad de la sintaxis y la posibilidad de volver a declarar variables mediante la forma corta := pueden llevar a errores de percepción.
Si se declara una variable con el mismo nombre en una función anidada o en un bloque de bucle que en el nivel superior, la variable externa quedará fuera de alcance (oscurecida — shadowed). En la mayoría de los casos, esto no es detectado por el compilador y puede causar errores, especialmente al trabajar con closures. Otro error común es declarar una nueva variable en un bloque if o en la inicialización del for, y luego intentar acceder a ella fuera del bloque.
Siempre hay que estar atento a los niveles de ámbito de visibilidad. No utilices los mismos nombres de variables en bloques anidados o funciones anónimas sin una necesidad real, evita nombres cortos y ten cuidado con el uso de :=.
Ejemplo de código:
package main import "fmt" func main() { x := 1 { x := 2 // oscurece x de main() fmt.Println("Inner x:", x) } fmt.Println("Outer x:", x) for i := 0; i < 3; i++ { x := i // se crea un nuevo x en cada iteración go func() { fmt.Println("Goroutine x:", x) }() } }
En este ejemplo, la variable externa x no se modifica, y una nueva x se crea dentro del bloque. En el segundo bucle, la variable x se captura en la función anidada — el resultado puede ser inesperado.
Características clave:
:= dentro de un bloque siempre crea una nueva variable, incluso si ya existe una externa.1. ¿Qué valor de la variable se imprimirá al final en el bloque anidado cuando hay un oscurecimiento?
El valor de la variable externa, porque la variable interna solo existe dentro del bloque.
2. ¿Qué sucederá si se intenta acceder a una variable declarada dentro de un bloque if/for fuera de este bloque?
El compilador mostrará un error: la variable está fuera del ámbito de visibilidad.
if true { y := 5 } fmt.Println(y) // error
3. ¿Cómo evitar un valor inesperado al crear goroutines en un bucle con una variable?
Pasar la variable como parámetro a la función:
for i := 0; i < 3; i++ { go func(val int) { fmt.Println(val) }(i) }
:= modifique una variable ya existente (creará una nueva).El bucle inicializa varias goroutines para procesamiento paralelo, pero dentro de la closure se utiliza la variable de bucle sin pasarse — todas las goroutines trabajan con su "último" valor.
Pros:
Contras:
Pasar la variable de bucle como parámetro a la closure — cada goroutine recibe su propio valor.
Pros:
Contras: