Valores Cero e Inicialización
Cada tipo de Go tiene un valor cero: el valor que una variable contiene antes de que le asignes algo.
Busca en todas las páginas de la documentación
Cada tipo de Go tiene un valor cero: el valor que una variable contiene antes de que le asignes algo.
Diseñar teniendo en cuenta los valores cero conduce a API más simples y menos comprobaciones de nil.
Declarar con var o asignar con new/make sin datos adicionales produce el valor cero del tipo.
Los tipos numéricos son 0, bool es false, las cadenas son "", y los tipos de referencia (punteros, slices, mapas, canales, funciones, interfaces) son nil.
Go idiomático a menudo hace que el valor cero sea útil para que los llamadores puedan inicializar una estructura a cero y usarla inmediatamente.
Tarjeta de receta de referencia rápida - lista para copiar y pegar.
package main
import "fmt"
type Config struct {
Host string
Port int
}
func main() {
var cfg Config // cero: Host "", Port 0
cfg.Host = "localhost"
cfg.Port = 8080
nums := make([]int, 0, 8) // slice vacío, no nil
fmt.Println(cfg, nums == nil)
}Cuándo recurrir a esto:
sync.Mutex, muchas estructuras de configuración).make para slices, mapas y canales cuando necesites un valor no nil listo para usar.T{...} cuando los valores predeterminados no sean suficientes.package main
import (
"bytes"
"fmt"
)
type Buffer struct {
buf bytes.Buffer
ok bool
}
func (b *Buffer) WriteString(s string) {
if !b.ok {
b.buf = *bytes.NewBuffer(nil)
b.ok = true
}
b.buf.WriteString(s)
}
func (b Buffer) String() string {
if !b.ok {
return ""
}
return b.buf.String()
}
func main() {
var b Buffer // valor cero utilizable: String() devuelve ""
b.WriteString("hello")
fmt.Println(b.String())
m := make(map[string]int)
m["a"] = 1
var sl []int // slice nil
sl = append(sl, 2)
fmt.Println(m, sl)
}Lo que esto demuestra:
make(map[K]V) devuelve un mapa vacío y no nil listo para la asignación.nil funcionan con append y len/cap devuelven 0.bytes.Buffer cambiaría el comportamiento del valor cero; diseña los campos deliberadamente.var x T asigna almacenamiento y establece los bits a cero para el tipo T.new(T) devuelve *T apuntando a almacenamiento inicializado a cero (raramente necesario frente a &T{}).make solo se aplica a slices, mapas y canales; asigna la estructura interna.T{v} o &T{v} establecen campos explícitamente mientras dejan otros en cero.| Tipo | Valor cero | ¿Utilizable sin inicialización? |
|---|---|---|
int, float, complex | 0 | Sí |
bool | false | Sí |
string | "" | Sí |
pointer, func, interface | nil | Solo después de comprobaciones de nil |
slice | nil | Sí para len, append, range |
map | nil | No para asignación - falla |
channel | nil | No para enviar/recibir - bloquea o falla |
struct | cada campo cero | Depende de los tipos de campo |
| Patrón | Ejemplo | Cuándo |
|---|---|---|
| Cero + campos establecidos | var c Config; c.Port = 8080 | Pocos campos, valores predeterminados seguros |
| Literal compuesto | Config{Host: "x"} | Valores conocidos en la creación |
make | make([]int, 0, n) | Preasignar capacidad |
| Función constructora | NewServer(cfg) | Validación o invariantes requeridos |
import "sync"
// El valor cero de Mutex es un mutex desbloqueado - listo para usar
var mu sync.Mutex
mu.Lock()
// Prefiere &T{} sobre new(T) para estructuras cuando puedas añadir campos más tarde
srv := &Server{}var m map[string]int; m["k"] = 1 falla. Solución: m = make(map[string]int) o un literal de mapa antes de la asignación.select o provoca un deadlock. Solución: make(chan T) o proteger con una comprobación de nil.var p *T; var i interface{} = p hace que i != nil sea verdadero mientras p == nil. Solución: devolver tipos concretos o comprobar explícitamente el nil tipado.int cero puede ser inválido para API de red. Solución: usar punteros *int o net.JoinHostPort con validación.var s []int y s := []int{} difieren para JSON (null vs []). Solución: elegir intencionadamente para la semántica de serialización.new - new(T) devuelve *T a ceros; muchas guías de estilo prefieren &T{} para estructuras. Solución: usar literales compuestos para mayor claridad.| Alternativa | Usar cuándo | No usar cuándo |
|---|---|---|
| Estructura con valor cero | Mutex, configuraciones simples | Los campos requeridos no tienen un valor predeterminado sensato |
make + append | Construir slices dinámicamente | Los arrays pequeños fijos son suficientes |
Campos punteros *int | Distinguir no establecido de cero | Cada campo se convertiría en un puntero (ruido) |
| Constructor/Builder | Validación compleja | Estructuras simples con 2-3 campos |
Cada campo se establece en su propio valor cero de forma recursiva.
Para struct{ A int; B string }, eso es 0 y "".
Ambos tienen len 0 y funcionan con append.
Difieren para == nil, codificación JSON y algunas API que tratan nil de forma especial.
Usa make cuando necesites un mapa o canal no nil, o un slice con len/cap específicos.
var s []int está bien cuando solo vas a usar append.
new(T) devuelve un puntero a almacenamiento inicializado a cero.
El análisis de escape decide entre pila y heap; new no fuerza la asignación en el heap por sí solo.
Las estructuras solo son comparables si todos los campos son comparables.
Los slices, mapas y funciones hacen que las estructuras no sean comparables.
Un valor de interfaz nil no tiene tipo dinámico ni valor.
Un puntero nil tipado asignado a una interfaz no es igual a una interfaz nil.
var a [3]int son tres ceros en la pila o en la estructura.
var s []int es una cabecera nil sin array de respaldo hasta make o append.
Solo cuando se requieren invariantes (nombre no vacío, puerto positivo).
Muchos tipos de la biblioteca estándar (bytes.Buffer, sync.Mutex) están diseñados para usarse con valor cero.
El time.Time cero es el 1 de enero de 1970 UTC - raramente un centinela útil.
Usa punteros o comprobaciones time.Time.IsZero().
type Outer struct{ Inner Inner }
o := Outer{Inner: Inner{Field: 1}}Los campos anidados no mencionados permanecen cero dentro de Inner.
La asignación copia la cabecera; el almacenamiento de respaldo se comparte.
Inicializa una vez y pasa con cuidado para evitar compartir involuntariamente.
Go pone a cero las asignaciones por seguridad en muchas rutas, pero no confíes en eso para secretos criptográficos.
Sobrescribe los búferes sensibles explícitamente cuando sea necesario.
var vs := en el momento de la declaraciónVersiones de Stack: Esta página fue escrita para Go 1.26.x (predeterminado GC Green Tea, go fix modernizers - verificar parche en la compilación), chi (última - verificar en la compilación), gin (última - verificar en la compilación), echo (última - verificar en la compilación), google.golang.org/grpc (última - verificar en la compilación), sigs.k8s.io/controller-runtime (última - verificar en la compilación), kubebuilder (última - verificar en la compilación), tinygo (última - verificar objetivos de placa en la compilación), wazero (última - verificar en la compilación), y golangci-lint (última - verificar conjunto de linters en la compilación).
Revisado por Chris St. John·Última actualización: 19 jul 2026