Variables y constantes: `var`, `:=`, `const` y `iota`
Go es un lenguaje de tipado estático pero con inferencia ergonómica. Aprender las cuatro formas de declarar valores — `var`, `:=`, `const` y `iota` — es la base de todo programa Go idiomático.
Declaración con var
La forma canónica de declarar una variable en Go es con la palabra clave var. Puedes especificar el tipo explícitamente, dejar que Go lo infiera, o incluso omitir el valor inicial (Go asigna el zero value del tipo).
package main
import "fmt"
func main() {
// 1. Tipo explícito y valor inicial
var name string = "Fernando"
// 2. Tipo inferido — Go deduce string del literal
var city = "Madrid"
// 3. Sin valor inicial — Go asigna el zero value (0, "", false, nil)
var age int // 0
var active bool // false
var nickname string // ""
fmt.Println(name, city, age, active, nickname)
}
Fernando Madrid 0 false A diferencia de JavaScript o Python, en Go una variable declarada siempre tiene un valor. Si no le das uno, Go le asigna el cero del tipo: 0 para números, "" para strings, false para bools, nil para punteros, slices y maps.
También puedes declarar varias variables a la vez con un bloque var (...):
package main
import "fmt"
var (
appName = "coding-challenges"
version = "1.0.0"
maxRetries = 5
debugMode = false
)
func main() {
fmt.Println(appName, version, maxRetries, debugMode)
}
coding-challenges 1.0.0 5 falseShort declaration con :=
Dentro de una función, Go ofrece una forma más compacta: el operador :=. Declara e inicializa la variable en un solo paso, infiriendo el tipo. Es la forma más usada en código idiomático.
package main
import "fmt"
func main() {
// Short declaration — solo dentro de funciones
name := "Fernando"
age := 30
height := 1.80
active := true
// Asignación múltiple
x, y, z := 1, 2, 3
// Swap idiomático sin variable temporal
a, b := 10, 20
a, b = b, a
fmt.Println(name, age, height, active)
fmt.Println(x, y, z)
fmt.Println(a, b)
}
Fernando 30 1.8 true
1 2 3
20 10El operador := no se puede usar a nivel de paquete (fuera de funciones). Para variables globales debes usar var. Tampoco puedes redeclarar todas las variables con := — al menos una debe ser nueva.
Scope y shadowing
Las variables en Go tienen scope de bloque: solo son visibles dentro del { ... } donde se declaran. Una variable declarada en un bloque interno con el mismo nombre que una externa la oculta (shadowing) — un error sutil pero común.
package main
import "fmt"
func main() {
count := 10
if true {
// Esto NO modifica el count externo, crea uno nuevo
count := 99
fmt.Println("dentro del if:", count) // 99
}
fmt.Println("fuera del if:", count) // 10 — el externo no cambió
// Para modificar el externo, usa = en vez de :=
if true {
count = 99
}
fmt.Println("ahora sí:", count) // 99
}
dentro del if: 99
fuera del if: 10
ahora sí: 99La herramienta go vet -vettool=$(which shadow) (o el linter golangci-lint) detecta automáticamente shadowing accidental. Es un buen reflejo activar este check en CI.
Constantes con const
Una constante es un valor inmutable conocido en tiempo de compilación. Se declara con const y solo admite tipos primitivos: números, strings y booleanos.
package main
import "fmt"
const Pi = 3.14159
const AppName = "coding-challenges"
// Bloque const — agrupa constantes relacionadas
const (
StatusActive = "active"
StatusInactive = "inactive"
StatusPending = "pending"
MaxConnections = 100
Timeout = 30
)
func main() {
fmt.Println(Pi, AppName)
fmt.Println(StatusActive, MaxConnections)
// const PiLocal = 3.14
// PiLocal = 3.15 // ❌ error de compilación: cannot assign to PiLocal
}
3.14159 coding-challenges
active 100Si declaras const Pi = 3.14159 sin tipo explícito, la constante es untyped: Go la adaptará al contexto donde se use (puede ser float32, float64, etc.). Si escribes const Pi float64 = 3.14159, queda fijada como float64.
iota: enumeraciones idiomáticas
iota es un identificador especial dentro de bloques const que arranca en 0 y se incrementa en cada línea. Es la forma idiomática de definir enumeraciones en Go.
package main
import "fmt"
// iota arranca en 0 y se incrementa por línea
const (
Sunday = iota // 0
Monday // 1
Tuesday // 2
Wednesday // 3
Thursday // 4
Friday // 5
Saturday // 6
)
// Tipos enumerados con un type dedicado
type LogLevel int
const (
Debug LogLevel = iota
Info
Warn
Error
)
// iota con expresiones — bit flags
const (
Read = 1 << iota // 1
Write // 2
Execute // 4
)
func main() {
fmt.Println(Sunday, Wednesday, Saturday)
fmt.Println(Debug, Info, Warn, Error)
fmt.Println(Read, Write, Execute, Read|Write)
}
0 3 6
0 1 2 3
1 2 4 3Cada bloque const ( ... ) reinicia iota a 0. Si necesitas saltarte valores, usa _ como nombre: const ( _ = iota; KB; MB; GB ) te da 1, 2, 3 saltándose el 0.