Introduction : l'instant de vérité pour le développeur Go
\n\nSi vous avez déjà écrit en Go (Golang) et utilisé des interfaces, vous avez sûrement rencontré ce message du compilateur :
\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\nSur 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\nDans 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\n1. Les interfaces en Go : petit rappel
\n\nAvant 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\nExemple d'une interface simple :
\n\ntype Speaker interface {\n Speak() string\n}\n\nDéfinissons maintenant une structure et une méthode :
\n\ntype 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\nIci, Dog implémente Speaker. Cela fonctionne avec Dog et *Dog :
var s Speaker\ns = Dog{Name: "Médor"} // ✅ OK\ns = &Dog{Name: "Rex"} // ✅ OK (Go déréférence automatiquement)\n\nJusque-là, tout est simple. Modifions maintenant la méthode pour utiliser un pointer receiver :
\n\nfunc (d *Dog) Speak() string {\n return "Ouaf ! Je suis " + d.Name\n}\n\nEt là, la magie opère.
\n\n2. Pointer receiver vs Value receiver : quelle différence ?
\n\nEn 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
Pourquoi est-ce important ? Parce que l'ensemble des méthodes d'un type dépend du receiver utilisé.
\n\nTable de vérité :
\n\n- \n
- Le type
Tpossède toutes les méthodes avec value receiver (pourT). \n - Le type
*Tpossède toutes les méthodes avec value receiver + pointer receiver. \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\nCe 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\n3. Analyse de l'erreur : « method has a pointer receiver »
\n\nRevenons à notre exemple. Si Speak() est déclaré avec *Dog, alors :
var s Speaker\ns = Dog{Name: "Médor"} // ❌ ERREUR\n// cannot use Dog{...} as Speaker...\n// method has a pointer receiver\n\nPourquoi ? Parce que Dog (pas un pointeur) n'a pas la méthode Speak() dans son ensemble. La méthode appartient uniquement à *Dog.
En revanche, cela fonctionne :
\n\ns = &Dog{Name: "Médor"} // ✅ OK\n\nAnalysons maintenant un exemple plus concret issu du code réel, souvent rencontré sur Stack Overflow.
\n\nExemple : interface et structure avec données
\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\