Historique de la question :
Go a mis en œuvre un concept simple mais puissant de méthodes et d'interfaces, basé sur le duck typing. Les méthodes peuvent être attachées uniquement aux types nommés (struct ou alias), et les interfaces sont un ensemble de méthodes. C'est la clé du polymorphisme et des abstractions sans besoin d'indiquer explicitement implements.
Problème :
Les programmeurs venant de Java ou C# s'attendent souvent à des mots-clés explicites implements ou extends, et se mélangent dans les différences entre les méthodes avec un récepteur par valeur et par pointeur, ce qui entraîne un comportement imprévisible et des erreurs lors de l'implémentation des interfaces.
Solution :
Définition d'une méthode et d'une interface :
type User struct { Name string } func (u User) Greet() string { return "Hello, " + u.Name } func (u *User) SetName(name string) { u.Name = name } type Greeter interface { Greet() string }
Caractéristiques clés :
Peut-on déclarer des méthodes pour un type-alias avec un type de base int ou string ?
Oui, si c'est un type nommé, par exemple :
type MyInt int func (m MyInt) Double() int { return int(m) * 2 }
Quelle est la différence entre l'implémentation d'une interface par des méthodes avec pointeur et par valeur ?
Si la méthode de l'interface est déclarée comme (T), alors à la fois T et *T implémentent l'interface. Si (*T), seul *T satisfait l'interface. Cela est critique pour passer une structure dans des fonctions qui acceptent des interfaces.
Comment fonctionne la "valeur zéro" pour l'interface et que se passe-t-il si on appelle une méthode sur une valeur nulle ?
Une variable d'interface non initialisée est égale à nil, une tentative d'appeler une méthode sur un champ nil va paniquer, à moins qu'un traitement explicite du nil-pointer ne soit réalisé.
Type déclaré avec des méthodes par pointeur (*T), l'interface attend des méthodes par valeur (T), et la structure ne compile pas lors de la tentative d'utilisation dans des interfaces. Tentative de déclarer une méthode pour une variable de type []User, et non pour le type User.
Avantages :
Inconvénients :
Toutes les méthodes implémentant les interfaces sont déclarées avec le récepteur correct. Les interfaces ne sont pas utilisées là où ce n'est pas nécessaire (type concret là où c'est possible, polymorphisme là où c'est nécessaire).
Avantages :
Inconvénients :