Constructeurs en Go : pas des « constructeurs », mais quelque chose de mieux
Si vous venez en Go du monde Python, Java ou C++, la première chose qui vous choquera probablement est qu'en Go il n'y a pas de constructeurs. Du tout. Pas de __init__, ClassName() ou new MyStruct() avec appel automatique.
Mais ne paniquez pas. Ce n'est pas un bug, c'est une fonctionnalité. En 2025, la communauté Go a finalement formulé les meilleures pratiques d'initialisation des objets. Et elles sont si élégantes que vous ne regretterez plus les constructeurs classiques.
Dans cet article, nous allons voir :
- Pourquoi il n'y a pas de constructeurs en Go et pourquoi c'est cool
- Comment les émuler sans douleur
- Les fonctions d'usine, le builder pattern et les interfaces fluides
- Les erreurs de débutants et les anti-patrons
- Des exemples réels de code de 2025
C'est parti !
Pourquoi n'y a-t-il pas de constructeurs en Go ? (Spoiler : c'est un choix délibéré)
Les concepteurs de Go (Rob Pike, Ken Thompson et autres) ont délibérément renoncé aux constructeurs. Pourquoi ?
- Simplicité. Les constructeurs génèrent souvent une logique cachée, de la magie et des appels implicites. Go est un langage où l'explicite est préférable à l'implicite.
- Contrôle. Vous décidez vous-même quand et comment initialiser une structure. Pas d'états cachés.
- Valeurs nulles. En Go, toute variable a toujours une valeur par défaut (nulle). Cela signifie que
var user Userest déjà un objet valide avec lequel on peut travailler.
Mais cela ne signifie pas que vous ne pouvez pas écrire des fonctions qui créent et configurent des objets. Vous le pouvez ! Et même vous le devez. Simplement, elles ne s'appellent pas « constructeurs », mais fonctions d'usine.
Technique de base : la fonction d'usine (NewXXX)
Le patron le plus courant est une fonction commençant par New. Elle retourne un pointeur vers une structure, garantissant que l'objet est créé correctement.
package main
import "fmt"
// User — structure simpletype User struct { Name string Email string Age int}
// NewUser — fonction d'usine (constructeur)func NewUser(name string, email string, age int) *User { return &User{ Name: name, Email: email, Age: age, }}
func main() { user := NewUser("Alice", "alice@example.com", 30) fmt.Println(user.Name) // Alice}C'est un classique. Mais que faire si les paramètres sont nombreux ? 5, 10, 15 ? Les passer dans l'ordre est une source de bugs. C'est là qu'interviennent les paramètres optionnels.
Meilleure pratique 2025 : les options fonctionnelles (Functional Options)
En 2025, les options fonctionnelles (functional options) sont de facto la norme pour configurer des objets complexes en Go. Ce patron a été popularisé par Dave Cheney et s'intègre parfaitement dans la philosophie du langage.
L'idée : vous passez à l'usine des fonctions-options qui modifient la structure avant de la retourner.
package main
import "fmt"
type Server struct { Host string Port int Timeout int // en secondes TLS bool}
// Option — type fonctionnel pour les optionstype Option func(*Server)
// WithTimeout — option pour définir le timeoutfunc WithTimeout(t int) Option { return func(s *Server) { s.Timeout = t }}
// WithTLS — option pour activer TLSfunc WithTLS(enabled bool) Option { return func(s *Server) { s.TLS = enabled }}
// NewServer — usine avec optionsfunc NewServer(host string, port int, opts ...Option) *Server { // valeurs par défaut de base s := &Server{ Host: host, Port: port, Timeout: 30, // par défaut TLS: false, } // application des options for _, opt := range opts { opt(s) } return s}\