Menu

Variables en Golang: var, :=, valores cero y sombreado

Cómo declarar variables en Go con var y la forma corta :=, qué son los valores cero, la asignación múltiple y los errores de sombreado y de variables sin usar que pillan a quien empieza con Go.

Esta página incluye editores ejecutables: edita, ejecuta y ve el resultado al instante.

Go tiene dos formas de declarar una variable: var, que funciona en cualquier sitio, y :=, una forma corta que funciona dentro de funciones e infiere el tipo.

Cada variable tiene un tipo fijo decidido en tiempo de compilación. Cuando le das un valor, Go infiere el tipo a partir de él, así que escribir también el tipo (var city string = "Lisbon") es válido pero redundante.

var frente a :=

var:=
Dóndea nivel de paquete y dentro de funcionessolo dentro de funciones
Tipoopcional; obligatorio cuando no hay valorsiempre inferido
Valor inicialopcional (si no, el valor cero)obligatorio
Redeclararnuncapermitido si al menos una variable de la izquierda es nueva

La elección idiomática dentro de una función:

  • x := value cuando tienes un valor inicial.
  • var x T cuando quieres el valor cero, lo que indica "vacío a propósito": var buf bytes.Buffer, var total int.
  • var x T = value cuando el tipo inferido no es el que quieres, por ejemplo var ratio float64 = 1 (un ratio := 1 a secas sería un int).

:= fuera de una función es un error de sintaxis:

./main.go:5:1: syntax error: non-declaration statement outside function body

Valores cero

Una variable declarada sin valor nunca contiene basura. Contiene el valor cero de su tipo:

TipoValor cero
enteros, flotantes0
boolfalse
string""
punteros, slices, maps, channels, funciones, interfacesnil
arrays, structscada elemento o campo con su valor cero

Las buenas APIs de Go se diseñan para que el valor cero sea útil: un sync.Mutex a cero está desbloqueado, un bytes.Buffer a cero está vacío y listo, y len, range y append funcionan con un slice nil. El que hay que vigilar es el map: leer un map nil devuelve valores cero, pero escribir en uno provoca un panic. Crea los maps con make o con un literal antes de guardar nada en ellos.

Declarar varias variables

El bloque var ( ... ) agrupa variables relacionadas a nivel de paquete. En una asignación múltiple como x, y = y, x, todas las expresiones de la derecha se evalúan antes de asignar nada, y por eso funciona el intercambio.

:= con varios nombres no redeclara nada mientras al menos un nombre de la izquierda sea nuevo. Los nombres que ya existen en el mismo ámbito simplemente se asignan. Esto es lo que permite reutilizar err:

f, err := os.Open("a.txt")   // declares f and err
g, err := os.Open("b.txt")   // declares g, assigns to the existing err

Si ninguno de los nombres es nuevo, es un error:

./main.go:7:4: no new variables on left side of :=

Usa un = normal para asignar a una variable que ya existe.

Las variables sin usar son errores

Una variable local que se declara pero nunca se lee detiene la compilación:

./main.go:9:2: declared and not used: x

No es un aviso que puedas desactivar. Borra la variable, úsala o, mientras depuras, siléncialo con el identificador vacío: _ = x. El identificador vacío también descarta los valores de retorno que no necesitas: _, err := fmt.Println("hi").

Las variables a nivel de paquete y los parámetros de función están exentos de esta regla.

Ámbito y sombreado

Una variable existe desde su declaración hasta el final del bloque que la contiene ({ ... }). Un := en un bloque interior crea una variable nueva, aunque exista fuera una con el mismo nombre. La exterior queda sombreada, no cambia:

El programa imprime inside: 42 y luego outside: 0. El := dentro del if declaró count y err como variables nuevas en el bloque interior, porque ninguna existía todavía ahí. Compila sin problemas y es una fuente clásica de bugs del tipo "mi valor ha desaparecido".

El arreglo es declarar antes err y asignar con =:

var err error
count, err = strconv.Atoi(input)

go vet no informa del sombreado por defecto. El analizador aparte shadow sí, y linters como golangci-lint pueden activarlo.

Nombres

  • Usa camelCase: maxRetries, userID. No max_retries.
  • Mantén las siglas en un mismo tipo de letra: userID, httpClient, parseURL, no userId.
  • Nombres cortos para ámbitos cortos: i en un bucle, r para un reader, err para un error. Nombres más largos y descriptivos para las variables a nivel de paquete.
  • Un nombre con mayúscula inicial a nivel de paquete (var Timeout) se exporta a otros paquetes. Consulta paquetes e imports.

Variables a nivel de paquete

Las variables declaradas fuera de las funciones viven durante todo el programa y se inicializan antes de que se ejecute main, en orden de dependencias. Son cómodas para configuración y cachés, y las comparten todas las goroutines. Si más de una goroutine escribe en una, protégela con un mutex o usa sync/atomic, o tendrás una carrera de datos.

Prefiere las constantes para los valores que nunca cambian. Una const no se puede modificar por accidente y no cuesta nada en tiempo de ejecución.

Preguntas frecuentes

¿Qué diferencia hay entre var y := en Go?

:= declara e inicializa una variable con un tipo inferido, y solo funciona dentro de funciones: count := 10. var funciona en cualquier sitio (también a nivel de paquete), te permite indicar el tipo y puede omitir el valor inicial para obtener el valor cero: var count int. Dentro de las funciones, el Go idiomático usa := cuando hay un valor inicial y var cuando quieres el valor cero.

¿Qué son los valores cero en Go?

Toda variable declarada sin valor recibe el valor cero de su tipo: 0 para los números, false para bool, "" para string y nil para punteros, slices, maps, channels, funciones e interfaces. Los structs reciben el valor cero de cada campo. En Go no hay variables sin inicializar.

¿Cómo arreglo "declared and not used" en Go?

Go rechaza una variable local que se asigna pero nunca se lee. Úsala, bórrala o, mientras depuras, asígnala al identificador vacío con _ = x. Las variables a nivel de paquete y los parámetros de función quedan exentos.

¿Cómo declaro una variable global en Go?

Usa var a nivel de paquete, fuera de cualquier función: var counter int. La forma corta := no está permitida ahí. Un nombre con mayúscula inicial (var Counter int) es visible para otros paquetes; uno en minúscula solo es visible en su propio paquete. Protege con un mutex las variables a nivel de paquete si hay goroutines que escriben en ellas.

Coddy programming languages illustration

Aprende a programar con Coddy

COMENZAR