«X does not implement Y» : décryptage de l'erreur avec le pointer receiver en Go

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Introduction : l'instant de vérité pour le développeur Go

\n\n

Si vous avez déjà écrit en Go (Golang) et utilisé des interfaces, vous avez sûrement rencontré ce message du compilateur :

\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

Sur Stack Overflow, cette question cumule des milliers de vues. Les débutants sont perplexes, les expérimentés haussent les épaules. Mais derrière cette erreur se cache un concept élégant et important : la différence entre value receiver et pointer receiver en langage Go.

\n\n

Dans cet article, nous allons explorer les coulisses du compilateur Go, analyser des exemples de code concrets et comprendre comment éviter ce piège. Vous apprendrez non seulement pourquoi l'erreur se produit, mais aussi comment elle est liée au système de types et aux interfaces.

\n\n

1. Les interfaces en Go : petit rappel

\n\n

Avant de plonger dans l'erreur, rappelons comment fonctionnent les interfaces Go. Contrairement à Java ou C++, une interface en Go est un ensemble de méthodes. Si un type implémente toutes les méthodes de l'interface, il satisfait automatiquement à cette interface (typage canard).

\n\n

Exemple d'une interface simple :

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

Définissons maintenant une structure et une méthode :

\n\n
type Dog struct {\n    Name string\n}\n\n// Value receiver — la méthode travaille sur une copie de la structure\nfunc (d Dog) Speak() string {\n    return "Ouaf ! Je suis " + d.Name\n}
\n\n

Ici, Dog implémente Speaker. Cela fonctionne avec Dog et *Dog :

\n\n
var s Speaker\ns = Dog{Name: "Médor"}  // ✅ OK\ns = &Dog{Name: "Rex"}  // ✅ OK (Go déréférence automatiquement)
\n\n

Jusque-là, tout est simple. Modifions maintenant la méthode pour utiliser un pointer receiver :

\n\n
func (d *Dog) Speak() string {\n    return "Ouaf ! Je suis " + d.Name\n}
\n\n

Et là, la magie opère.

\n\n

2. Pointer receiver vs Value receiver : quelle différence ?

\n\n

En Go, les méthodes peuvent avoir deux types de récepteurs (receivers) :

\n\n
    \n
  • Value receiver (t Type) — la méthode reçoit une copie de la valeur.
  • \n
  • Pointer receiver (t *Type) — la méthode reçoit un pointeur vers la valeur d'origine.
  • \n
\n\n

Pourquoi est-ce important ? Parce que l'ensemble des méthodes d'un type dépend du receiver utilisé.

\n\n

Table de vérité :

\n\n
    \n
  • Le type T possède toutes les méthodes avec value receiver (pour T).
  • \n
  • Le type *T possède toutes les méthodes avec value receiver + pointer receiver.
  • \n
\n\n

Autrement dit : le pointeur reçoit un « bonus » d'ensemble de méthodes, tandis que la valeur ne possède que celles déclarées avec un value receiver.

\n\n

Ce n'est pas un bug, mais une fonctionnalité de conception de Go. Le compilateur ne peut pas prendre automatiquement l'adresse d'une valeur si celle-ci n'est pas adressable (par exemple, le résultat d'une fonction ou un littéral).

\n\n

3. Analyse de l'erreur : « method has a pointer receiver »

\n\n

Revenons à notre exemple. Si Speak() est déclaré avec *Dog, alors :

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

Pourquoi ? Parce que Dog (pas un pointeur) n'a pas la méthode Speak() dans son ensemble. La méthode appartient uniquement à *Dog.

\n\n

En revanche, cela fonctionne :

\n\n
s = &Dog{Name: "Médor"}  // ✅ OK
\n\n

Analysons maintenant un exemple plus concret issu du code réel, souvent rencontré sur Stack Overflow.

\n\n

Exemple : interface et structure avec données

\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