«X does not implement Y»: analizando el error con pointer receiver en Go

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: el momento de la verdad para el desarrollador Go

\n\n

Si alguna vez has programado en Go (Golang) y has usado interfaces, seguramente te has encontrado con este mensaje del compilador:

\n\n
cannot use x (variable of type *MyStruct) as type MyInterface value in assignment:\n*MyStruct does not implement MyInterface (method GetName has a pointer receiver)
\n\n

En Stack Overflow, esta pregunta acumula miles de visitas. Los principiantes se quedan perplejos, los experimentados se encogen de hombros. Pero en realidad, detrás de este error hay un concepto elegante e importante: la diferencia entre value receiver y pointer receiver en el lenguaje Go.

\n\n

En este artículo, exploraremos «bajo el capó» del compilador Go, analizaremos ejemplos reales de código y entenderemos cómo evitar esta trampa. Aprenderás no solo por qué ocurre el error, sino también cómo se relaciona con el sistema de tipos e interfaces.

\n\n

1. Interfaces en Go: breve introducción

\n\n

Antes de sumergirnos en el error, recordemos cómo funcionan las interfaces de Go. A diferencia de Java o C++, en Go una interfaz es un conjunto de métodos. Si un tipo implementa todos los métodos de la interfaz, automáticamente satisface esa interfaz (tipado pato).

\n\n

Ejemplo de una interfaz simple:

\n\n
type Speaker interface {\n    Speak() string\n}
\n\n

Ahora definamos una estructura y un método:

\n\n
type Dog struct {\n    Name string\n}\n\n// Value receiver — el método trabaja con una copia de la estructura\nfunc (d Dog) Speak() string {\n    return "¡Guau! Soy " + d.Name\n}
\n\n

Aquí, Dog implementa Speaker. Funciona tanto con Dog como con *Dog:

\n\n
var s Speaker\ns = Dog{Name: "Bobby"}  // ✅ OK\ns = &Dog{Name: "Rex"}  // ✅ OK (Go desreferencia automáticamente)
\n\n

Todo simple por ahora. Ahora cambiemos el método a pointer receiver:

\n\n
func (d *Dog) Speak() string {\n    return "¡Guau! Soy " + d.Name\n}
\n\n

Y aquí comienza la magia.

\n\n

2. Pointer receiver vs Value receiver: ¿cuál es la diferencia?

\n\n

En Go, los métodos pueden tener dos tipos de receptores (receivers):

\n\n
    \n
  • Value receiver (t Type) — el método recibe una copia del valor.
  • \n
  • Pointer receiver (t *Type) — el método recibe un puntero al valor original.
  • \n
\n\n

¿Por qué es importante? Porque el conjunto de métodos de un tipo depende del receiver que se utilice.

\n\n

Tabla de verdad:

\n\n
    \n
  • El tipo T tiene todos los métodos con value receiver (para T).
  • \n
  • El tipo *T tiene todos los métodos con value receiver + pointer receiver.
  • \n
\n\n

En otras palabras: el puntero obtiene un «conjunto adicional» de métodos, mientras que el valor solo tiene aquellos declarados con value receiver.

\n\n

Esto no es un error, sino una característica del diseño de Go. El compilador no puede tomar automáticamente la dirección de un valor si este no es direccionable (por ejemplo, el resultado de una función o un literal).

\n\n

3. Análisis del error: «method has a pointer receiver»

\n\n

Volvamos a nuestro ejemplo. Si Speak() está declarado con *Dog, entonces:

\n\n
var s Speaker\ns = Dog{Name: "Bobby"}  // ❌ ERROR\n// cannot use Dog{...} as Speaker...\n// method has a pointer receiver
\n\n

¿Por qué? Porque Dog (no puntero) no tiene el método Speak() en su conjunto. El método pertenece solo a *Dog.

\n\n

Pero esto sí funciona:

\n\n
s = &Dog{Name: "Bobby"}  // ✅ OK
\n\n

Ahora analicemos un ejemplo más realista de código que a menudo se encuentra en Stack Overflow.

\n\n

Ejemplo: interfaz y estructura con datos

\n\n
package main\n\nimport "fmt"\n\ntype User interface {\n    GetID() int\n    SetName(name string)\n}\n\ntype Admin struct {\n    ID   int\                

Blogs

Book Recommendations