Value vs Pointer Receiver en Go : que choisir ?

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

Value receiver vs. pointer receiver : un duel qui ne s'éteint pas

\n\n

Si vous avez déjà écrit en Go, vous avez forcément rencontré cette question. Vous ouvrez Stack Overflow — et là, des milliers de vues, des centaines de commentaires, et un débutant sur deux (et pas que) se creuse la tête : "Que dois-je choisir ? Value receiver ou pointer receiver ?"

\n\n

Divulgâchage : il n'y a pas de réponse unique valable pour tous les cas. Mais il existe des règles claires qui vous aideront à ne pas vous tromper dans 95% des cas. Et aujourd'hui, nous allons les décortiquer une fois pour toutes.

\n\n

Dans cet article, je ne vais pas simplement traduire une documentation aride. Nous allons parcourir des cas concrets, examiner les performances, la mutabilité, les interfaces et même la façon dont la communauté Go perçoit les différentes approches. C'est parti !

\n\n

Qu'est-ce qu'un receiver en Go ?

\n\n

Pour ceux qui découvrent le langage : un receiver est un paramètre qui lie une fonction à un type. C'est ainsi que les méthodes sont implémentées en Go.

\n\n
type User struct {\n    Name string\n    Age  int\n}\n\n// Value receiver\nfunc (u User) Greet() string {\n    return "Bonjour, je suis " + u.Name\n}\n\n// Pointer receiver\nfunc (u *User) Birthday() {\n    u.Age++\n}\n
\n\n

Dans le premier cas, nous travaillons avec une copie de la structure. Dans le second, avec un pointeur vers l'original. Cela semble un détail. Mais de ce détail découlent des décisions architecturales entières.

\n\n

Quand utiliser le value receiver

\n\n

Commençons par l'option la plus simple et la plus sûre.

\n\n

1. La méthode ne modifie pas le récepteur

\n\n

C'est la règle d'or. Si la méthode se contente de lire les données et ne change rien — utilisez le value receiver. C'est sûr, prévisible et clair.

\n\n
type Rectangle struct {\n    Width, Height float64\n}\n\nfunc (r Rectangle) Area() float64 {\n    return r.Width * r.Height\n}\n
\n\n

Personne ne s'attend à ce que le calcul de la surface modifie le rectangle lui-même. Le value receiver est ici le choix idéal.

\n\n

2. Les petites structures

\n\n

Si votre structure ne contient que quelques champs (comme Rectangle ci-dessus), la copie ne coûte pratiquement rien. De plus, cela peut être plus rapide que de travailler avec un pointeur, car les données se trouvent sur la pile, et non sur le tas.

\n\n

3. Sécurité et immutabilité

\n\n

Parfois, vous voulez délibérément garantir que la méthode ne modifiera pas les données d'origine. Le value receiver vous offre cette garantie au niveau du compilateur.

\n\n
type Config struct {\n    Timeout int\n}\n\nfunc (c Config) WithTimeout(t int) Config {\n    c.Timeout = t\n    return c\n}\n
\n\n

C'est le modèle de programmation fonctionnelle : la méthode retourne une nouvelle copie, sans toucher à l'original. Idéal pour des configurations immuables.

\n\n

Quand choisir le pointer receiver

\n\n

C'est là que les choses deviennent intéressantes. Le pointer receiver est un outil puissant, mais il faut l'utiliser avec précaution.

\n\n

1. La méthode modifie le récepteur

\n\n

C'est le cas le plus évident. Si vous écrivez SetName, UpdateStatus ou Increment — vous avez besoin d'un pointeur.

\n\n
type Counter struct {\n    Value int\n}\n\nfunc (c *Counter) Increment() {\n    c.Value++\n}\n
\n\n

Sans pointeur, vous incrémenteriez une copie, et l'original resterait inchangé. Une erreur classique de débutant.

\n\n

2. Les grandes structures

\n\n

Si votre structure pèse une centaine d'octets ou plus, la copie à chaque appel de méthode est coûteuse. Surtout si la méthode est appelée dans une boucle.

\n\n
type LargeData struct {\n    Buffer [1024]byte\n    Meta   map[string]interface{}\n}\n\n// Copier une telle structure à chaque appel est une douleur
func (l *LargeData) Process() {
    // on travaille avec l'original
}
\n\n

Ici, le pointer receiver n'est pas qu'une commodité, c'est une optimisation des performances.

\n\n

3. Quand la structure contient un mutex ou

Blogs

Book Recommendations