Punteros y el Operador Address-of
Los punteros almacenan la dirección de un valor, permitiendo la mutación entre límites de funciones y evitando copias grandes.
Busca en todas las páginas de la documentación
Los punteros almacenan la dirección de un valor, permitiendo la mutación entre límites de funciones y evitando copias grandes.
Go tiene punteros pero no aritmética de punteros, manteniendo la seguridad de memoria sencilla.
&x toma la dirección de x; *p desreferencia el puntero p.
Los argumentos de función se pasan por valor; comparte mutaciones pasando punteros.
Los receptores de métodos pueden ser valores o punteros; los receptores de puntero son necesarios cuando los métodos modifican el estado.
Tarjeta de receta de referencia rápida - lista para copiar y pegar.
package main
import "fmt"
func increment(n *int) {
*n++ // Desreferencia el puntero y lo incrementa
}
func main() {
count := 10
increment(&count) // Pasa la dirección de count
fmt.Println(count) // Imprime 11
}Cuándo usar esto:
*T.package main
import "fmt"
// Config es una estructura de ejemplo.
type Config struct {
Host string
Port int
}
// SetPort es un método con un receptor de puntero que modifica la estructura.
func (c *Config) SetPort(p int) {
c.Port = p // Modifica el campo Port de la estructura original
}
// clone copia una estructura Config por valor.
func clone(cfg Config) Config {
return cfg // La estructura se copia por valor
}
func main() {
cfg := Config{Host: "localhost", Port: 8080}
cfg.SetPort(9090) // Llama al método receptor de puntero, cfg.Port ahora es 9090
copy := clone(cfg) // Crea una copia de cfg
copy.Port = 1 // Modifica la copia; cfg.Port permanece sin cambios
fmt.Println(cfg.Port, copy.Port) // Imprime 9090 1
var p *int // Declara un puntero a int, inicialmente nil
if p != nil {
// Este bloque no se ejecutará porque p es nil
fmt.Println(*p) // Desreferenciar un puntero nil provocaría un pánico
} else {
fmt.Println("p is nil") // Imprime "p is nil"
}
}Lo que esto demuestra:
SetPort muta cfg in situ.copy.Port no afecta a cfg.& al llamar a métodos con receptor de puntero en valores direccionables.&.new(T) asigna un T inicializado a cero y devuelve *T; el código idiomático a menudo usa &T{}.nil se comparan igual entre sí y con nil sin tipo en un contexto de puntero tipado.nil.| Aspecto | Por valor T | Por puntero *T |
|---|---|---|
| Costo de copia | Estructura completa | Palabra de puntero |
| Mutación en el llamado | No (a menos que se devuelva) | Sí, a través de desreferencia |
nil posible | No para valor | Sí |
omitempty de JSON | N/A | Omite punteros nulos |
| Usa receptor de puntero cuando | Usa receptor de valor cuando |
|---|---|
| El método muta el receptor | Tipo pequeño e inmutable |
| La estructura es grande | Consistencia con la API existente |
| Debe compartir estado de mutex | Los métodos de valor cero deben funcionar (time.Time) |
// Campo opcional
type User struct {
Name string
Nick *string // nil significa no establecido
}
// No pases un puntero a una variable de bucle sin copiarlo
for i := 0; i < 3; i++ {
n := i // Crea una copia local de i para cada iteración
go func() { fmt.Println(&n) }() // Ahora cada goroutine imprime un valor diferente
}*p cuando p == nil provoca un pánico. Solución: comprueba p != nil o garantiza la construcción.return (*T)(nil), err todavía hace que la interfaz no sea nil. Solución: devuelve una interfaz nil o un tipo de valor concreto.item := item dentro del bucle.| Alternativa | Úsala cuando | No la uses cuando |
|---|---|---|
| Devolver nuevo valor | Transformaciones inmutables | Estructuras grandes o muchas mutaciones |
Puntero *T | Mutación, campos opcionales | Enteros/booleanos diminutos (usa valor) |
| Interfaz | Ocultar el tipo concreto | Necesitas distinguir claramente entre nil y valor |
sync/atomic | Contadores concurrentes | Campos de estructura generales |
No, no puedes incrementar punteros como en C.
Usa slices para el recorrido de buffers.
Go toma automáticamente la dirección para receptores de puntero cuando el valor es direccionable: cfg.SetPort(1) llama a (&cfg).SetPort(1).
No, &m[key] no es válido porque el almacenamiento del mapa puede moverse.
Copia a una variable local y apunta a esa si es necesario temporalmente.
new(T) devuelve *T a un T inicializado a cero.
make es solo para slices, mapas y canales.
Los valores de puntero se comparan con == y != si apuntan a la misma variable o ambos son nil.
No comparan el contenido de los slices.
Tomar &local puede hacer que local "escape" al heap si el puntero sobrevive a la función.
El compilador decide; no puedes forzar la asignación en pila de forma fiable.
*string con omitempty omite los campos no establecidos en JSON.
Usa punteros para campos de API opcionales; usa valores para los requeridos.
Puntero a puntero - raro en código de aplicación.
Aparece en interoperabilidad con C o algunas APIs genéricas.
Sí, el análisis de escape mueve las locales al heap cuando su dirección escapa.
Esto es seguro en Go, a diferencia de devolver desde la pila en C.
Establece a nil o reemplaza con &T{} para un nuevo valor cero.
Elige según si la ausencia o el vacío importa a los llamadores.
Mutex no debe copiarse después del primer uso.
Los receptores de puntero en tipos que incrustan Mutex evitan la copia accidental por métodos de valor.
Una puerta de escape de bajo nivel para interoperabilidad y optimizaciones avanzadas.
Evita usarlo en código de aplicación a menos que realmente necesites las reglas del paquete unsafe.
newVersiones de Stack: Esta página fue escrita para Go 1.26.x (predeterminado de GC Green Tea, go fix modernizers - verifica el parche en la compilación), chi (última versión - verifica en la compilación), gin (última versión - verifica en la compilación), echo (última versión - verifica en la compilación), google.golang.org/grpc (última versión - verifica en la compilación), sigs.k8s.io/controller-runtime (última versión - verifica en la compilación), kubebuilder (última versión - verifica en la compilación), tinygo (última versión - verifica los objetivos de la placa en la compilación), wazero (última versión - verifica en la compilación) y golangci-lint (última versión - verifica el conjunto de linters en la compilación).
Revisado por Chris St. John·Última actualización: 18 jul 2026