Introdução: o momento da verdade para o desenvolvedor Go
\n\nSe você já escreveu em Go (Golang) e usou interfaces, certamente já encontrou esta mensagem do compilador:
\n\ncannot 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\nNo Stack Overflow, esta pergunta acumula milhares de visualizações. Iniciantes ficam perplexos, experientes — encolhem os ombros. Mas, na verdade, por trás deste erro existe um conceito elegante e importante: a diferença entre value receiver e pointer receiver na linguagem Go.
\n\nNeste artigo, vamos olhar «sob o capô» do compilador Go, analisar exemplos reais de código e entender como evitar essa armadilha. Você aprenderá não apenas por que o erro ocorre, mas também como ele se relaciona com o sistema de tipos e interfaces.
\n\n1. Interfaces em Go: um breve resumo
\n\nAntes de mergulharmos no erro, vamos relembrar como funcionam as interfaces Go. Diferente de Java ou C++, em Go uma interface é um conjunto de métodos. Se um tipo implementa todos os métodos da interface, ele automaticamente satisfaz essa interface (duck typing).
\n\nExemplo de uma interface simples:
\n\ntype Speaker interface {\n Speak() string\n}\n\nAgora vamos definir uma struct e um método:
\n\ntype Dog struct {\n Name string\n}\n\n// Value receiver — o método trabalha com uma cópia da struct\nfunc (d Dog) Speak() string {\n return "Au! Eu sou " + d.Name\n}\n\nAqui, Dog implementa Speaker. Funciona tanto com Dog quanto com *Dog:
var s Speaker\ns = Dog{Name: "Bobby"} // ✅ OK\ns = &Dog{Name: "Rex"} // ✅ OK (Go desreferencia automaticamente)\n\nAté aqui, tudo simples. Agora vamos mudar o método para pointer receiver:
\n\nfunc (d *Dog) Speak() string {\n return "Au! Eu sou " + d.Name\n}\n\nE aí começa a mágica.
\n\n2. Pointer receiver vs Value receiver: qual a diferença?
\n\nEm Go, os métodos podem ter dois tipos de receptores (receivers):
\n\n- \n
- Value receiver
(t Type)— o método recebe uma cópia do valor. \n - Pointer receiver
(t *Type)— o método recebe um ponteiro para o valor original. \n
Por que isso é importante? Porque o conjunto de métodos de um tipo depende de qual receiver é usado.
\n\nTabela verdade:
\n\n- \n
- O tipo
Tpossui todos os métodos com value receiver (paraT). \n - O tipo
*Tpossui todos os métodos com value receiver + pointer receiver. \n
Em outras palavras: o ponteiro recebe um «conjunto bônus» de métodos, enquanto o valor tem apenas aqueles declarados com value receiver.
\n\nIsso não é um bug, mas uma característica do design do Go. O compilador não pode pegar automaticamente o endereço de um valor se ele não for endereçável (por exemplo, resultado de uma função ou literal).
\n\n3. Análise do erro: «method has a pointer receiver»
\n\nVoltemos ao nosso exemplo. Se Speak() for declarado com *Dog, então:
var s Speaker\ns = Dog{Name: "Bobby"} // ❌ ERRO\n// cannot use Dog{...} as Speaker...\n// method has a pointer receiver\n\nPor quê? Porque Dog (não ponteiro) não possui o método Speak() em seu conjunto. O método pertence apenas a *Dog.
Já isso funciona:
\n\ns = &Dog{Name: "Bobby"} // ✅ OK\n\nAgora vamos analisar um exemplo mais realista de código, frequentemente encontrado no Stack Overflow.
\n\nExemplo: interface e struct com dados
\n\npackage main\n\nimport "fmt"\n\ntype User interface {\n GetID() int\n SetName(name string)\n}\n\ntype Admin struct {\n ID int\