Saltar al contenido principal
eLearner.app
Módulo 5 · Lección 2 de 522/50 en el curso~14 min
Lecciones del módulo (2/5)

Métodos: receptor de valor vs de puntero

Un método en Go es una función con un receptor: un especial parámetro declarado entre func y el nombre del método, que vincula el método a un tipo. No hay clases: los métodos se pueden definir en cualquier tipo con nombre declarado en el paquete actual.

Sintaxis

Go
type Person struct {
    Name string
}

func (p Person) Greet() string {
    return "ciao " + p.Name
}

p := Person{Name: "Ada"}
fmt.Println(p.Greet())   // "ciao Ada"

El receptor p Person convierte a Greet en un método de Person. Dentro del método, p es una variable como cualquier otra.

Receptor de valor versus receptor de puntero

Go
// VALUE receiver: operates on a COPY of the value
func (p Person) NameUpper() string {
    return strings.ToUpper(p.Name)
}

// POINTER receiver: operates on the original value, can mutate it
func (p *Person) Rename(n string) {
    p.Name = n
}

Con un receptor de puntero puedes modificar el receptor y los cambios son visibles fuera del método. Con un receptor de valor no puedes; solo modifique la copia local.

Go
p := Person{Name: "Ada"}
p.Rename("Grace")
fmt.Println(p.Name)   // "Grace" — change is visible

Cuándo utilizar un receptor de puntero

Reglas prácticas, por orden de prioridad:

  1. Debes modificar el receptor → receptor de puntero. Obligatorio.
  2. La estructura es grande (docenas de campos, matrices dentro) → puntero receptor para evitar copias costosas.
  3. Consistencia: si AL MENOS un método del tipo tiene un receptor de puntero, use un receptor de puntero para los demás también. Una convención muy importante para interfaces (Módulo 6).
  4. Tipos de "valores" pequeños e inmutables (tiempo.Tiempo, números complejos, pequeños estructuras) → receptor de valor, más legible.

Métodos en tipos que no son estructuras

Puede definir métodos en cualquier tipo NAMED declarado en su paquete:

Go
type Celsius float64

func (c Celsius) ToFahrenheit() float64 {
    return float64(c)*9/5 + 32
}

t := Celsius(20)
fmt.Println(t.ToFahrenheit())  // 68

No puede definirlos en tipos de otros paquetes (por ejemplo, int, string): debe Primero cree un tipo con nombre local.

Pruébalo

Ejercicio#go.m5.l2.e1
Intentos: 0Cargando...

Agregue un método de cadena Greet() (receptor de valores) a Persona que devuelva 'ciao <Nombre>'.

Cargando editor...
Mostrar pista

Receptor entre paréntesis ANTES del nombre del método.

Solución disponible después de 3 intentos

Ejercicio#go.m5.l2.e2
Intentos: 0Cargando...

Agregue un método Rename (n cadena) con un receptor POINTER que cambia p.Name.

Cargando editor...
Mostrar pista

Receptor de puntero: `(p *Person)`.

Solución disponible después de 3 intentos

Cuestionario#go.m5.l2.e3
Listo

¿Cuándo debería utilizar un receptor de puntero (p *T)?

Go
func (t ?T) M() { ... }
Opciones de respuesta

Resumen

  • Método = función con receptor: func (r T) Name(...) ... { ... }.
  • Receptor de valor: opera sobre una copia; Receptor de puntero: funciona sobre el original.
  • Go realiza la conversión T*T automáticamente en el sitio de la llamada.
  • Receptor de puntero cuando: mutación + estructura grande + coherencia con otros métodos del tipo.
  • Nunca mezcle receptores de valor y puntero del mismo tipo.
  • Los métodos van en tipos NAMED en el paquete actual (incluido el no estructurado).