0Pricing
Go Academy · Lección

Receivers por puntero en métodos

Modificación del estado de un struct mediante receivers por puntero

Receivers por puntero en métodos es una lección gratuita de Go Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Go Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Go Academy incluye 4 lecciones en total.

Repaso: receptor por valor frente a receptor por puntero

Un receptor por valor opera sobre una copia de la estructura. Un receptor por puntero opera sobre la original. Utilice receptores por puntero siempre que un método necesite modificar el estado.

Modificación con un receptor por puntero

Solo un receptor por puntero puede modificar la estructura:

package main
import "fmt"

type Stack struct{ items []int }

func (s *Stack) Push(v int) { s.items = append(s.items, v) }
func (s *Stack) Pop() int {
    n := len(s.items) - 1
    v := s.items[n]
    s.items = s.items[:n]
    return v
}

func main() {
    var st Stack
    st.Push(1); st.Push(2)
    fmt.Println(st.Pop()) // 2
}

Regla de coherencia

Si algún método de un tipo necesita un receptor por puntero, todos sus métodos deben utilizar receptores por puntero. Mezclarlos provoca problemas para satisfacer interfaces:

package main
import "fmt"

type Counter struct{ n int }

func (c *Counter) Inc()   { c.n++ }   // pointer
func (c *Counter) Val() int { return c.n } // pointer too

func main() {
    c := &Counter{}
    c.Inc(); c.Inc()
    fmt.Println(c.Val()) // 2
}

Satisfacción de interfaces

Un método con receptor por puntero solo forma parte del conjunto de métodos de *T, no de T. Esto afecta a la satisfacción de interfaces:

package main
import "fmt"

type Writer interface{ Write([]byte) }

type File struct{ name string }
func (f *File) Write(b []byte) { fmt.Println(string(b)) }

func main() {
    var w Writer = &File{"out.txt"} // OK
    // var w Writer = File{} — compile error
    w.Write([]byte("hello"))
}

Toma automática de direcciones

Go toma automáticamente la dirección al llamar a un método con receptor por puntero sobre un valor direccionable:

package main
import "fmt"

type Box struct{ V int }
func (b *Box) Double() { b.V *= 2 }

func main() {
    b := Box{5}
    b.Double()          // Go does (&b).Double()
    fmt.Println(b.V)    // 10
}

Valores no direccionables

No puede llamar a métodos con receptor por puntero sobre valores no direccionables (elementos de mapas y valores devueltos por funciones que no se han asignado a variables):

package main

type T struct{ V int }
func (t *T) Set(v int) { t.V = v }

func getT() T { return T{} }

func main() {
    var t T
    t.Set(1)       // OK — t is addressable
    // getT().Set(1) — ERROR: cannot take address of getT()
    _ = t
}

Receptores de estructuras grandes

Utilice siempre receptores por puntero para las estructuras grandes, a fin de evitar copias costosas en cada llamada a un método:

package main

type Image struct{ pixels [1024][1024]uint8 }

// Value receiver copies 1MB per call!
func (img Image) Bad() uint8 { return img.pixels[0][0] }

// Pointer receiver — zero copy
func (img *Image) Good() uint8 { return img.pixels[0][0] }

func main() { _ = Image{} }

Receptores de puntero nil

Los métodos con receptores por puntero pueden gestionar nil correctamente:

package main
import "fmt"

type List struct{ head *node }
type node struct{ val int; next *node }

func (l *List) Len() int {
    if l == nil { return 0 }
    count := 0
    for n := l.head; n != nil; n = n.next { count++ }
    return count
}

func main() {
    var l *List
    fmt.Println(l.Len()) // 0
}

Inserción y receptores por puntero

Al insertar un tipo con receptores por puntero, la estructura externa también debe utilizarse como puntero para obtener los métodos promovidos:

package main
import "fmt"

type Base struct{ V int }
func (b *Base) Set(v int) { b.V = v }

type Derived struct{ Base }

func main() {
    d := &Derived{}
    d.Set(42)           // promoted pointer-receiver method
    fmt.Println(d.V)    // 42
}

Copiar mutexes

No copie nunca una estructura que contenga un sync.Mutex; utilice siempre un receptor por puntero o pase la estructura mediante un puntero. Copiar un mutex bloqueado provoca un interbloqueo:

package main
import "sync"

type Safe struct {
    mu sync.Mutex
    v  int
}

// Correct: pointer receiver
func (s *Safe) Set(v int) {
    s.mu.Lock()
    defer s.mu.Unlock()
    s.v = v
}

func main() { _ = Safe{} }

go vet detecta errores

Ejecute go vet ./... para detectar errores comunes relacionados con receptores por puntero, como copiar mutexes y bloqueos. Forma parte de las canalizaciones de go build y de las comprobaciones de CI.

Comprobación rápida

¿En el conjunto de métodos de qué tipos se encuentra un método con receptor por puntero?

Repaso

Conclusiones principales:

  • Los receptores por puntero modifican datos; los receptores por valor no
  • Mantenga el mismo tipo de receptor en todos los métodos de un tipo
  • Solo *T satisface interfaces que requieren métodos con receptores por puntero
  • No copie nunca estructuras con mutexes; utilice receptores por puntero

Propuesta de práctica

Implemente una estructura Queue con los métodos Enqueue(int), Dequeue() (int, bool) y Len() int, todos con receptores por puntero y respaldados por un slice []int.

Preguntas frecuentes

¿La lección «Receivers por puntero en métodos» es gratis?

Sí — el texto completo de «Receivers por puntero en métodos» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Go Academy, actualiza a CoddyKit PRO. El curso de Go Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Receivers por puntero en métodos»?

Modificación del estado de un struct mediante receivers por puntero Practicas Go Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Go Academy?

No se requiere experiencia previa. Go Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.

¿Cuánto tiempo toma la lección «Receivers por puntero en métodos»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Go Academy?

Sí. Cada lección de Go Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. ¿Qué son los punteros?
  2. Punteros y funciones
  3. Receivers por puntero en métodos
  4. new() y cuándo usar punteros
← Volver a Go Academy