ProgrammationDéveloppeur Go

Décrivez les caractéristiques de travail avec des paramètres optionnels et des valeurs par défaut en Go, et comment réaliser des interfaces de fonctions flexibles avec un minimum de rigidité

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Go ne prend pas en charge les paramètres optionnels et les valeurs par défaut pour les arguments de fonction - chaque fonction accepte uniquement l'ensemble d'arguments spécifié dans son fidèle signature. Cette décision de conception est liée à la simplicité générale du modèle et à la prévisibilité du code.

Historique de la question

Dans d'autres langages, comme Python ou C++, les paramètres optionnels/par défaut permettent de définir de manière flexible le comportement de la fonction. En Go, cela a été sacrifié au nom de la lisibilité et de l'ambiguïté.

Problème

Lorsqu'il est nécessaire de rendre une API flexible, il n'est pas possible de simplement définir des valeurs par défaut - il faut transmettre explicitement tous les paramètres ou utiliser des motifs de contournement. Cela complique le soutien d'un grand nombre d'options et peut entraîner une augmentation du nombre de fonctions surchargées.

Solution

En Go, deux approches sont utilisées pour cette flexibilité :

  1. Paramètre-structure - une structure est créée avec un ensemble de champs-options, qui peut être transmise à une fonction. À l'intérieur de la structure, les valeurs par défaut peuvent être définies explicitement.
  2. Fonctions variadiques (modèle des options fonctionnelles) - un modèle qui consiste à passer des fonctions de configuration qui modifient la configuration d'un objet.

Exemple de l'approche par la structure :

type QueryOptions struct { Limit int Offset int } func QueryDB(opts QueryOptions) { if opts.Limit == 0 { opts.Limit = 10 // défaut } // ... } QueryDB(QueryOptions{Limit: 100})

Ou par des options fonctionnelles :

type Config struct { Timeout int } type Option func(*Config) func WithTimeout(t int) Option { return func(cfg *Config) { cfg.Timeout = t } } func Do(opts ...Option) { cfg := Config{Timeout: 5} // défaut for _, o := range opts { o(&cfg) } // ... } Do(WithTimeout(10)) // appel avec option Do() // appel avec défaut

Caractéristiques clés :

  • Pas de paramètres optionnels/de défaut au niveau du langage
  • La flexibilité est atteinte soit par des structures, soit par un modèle fonctionnel
  • Tout est explicite, sans magie - il est toujours clair ce qui est transmis et comment

Questions piégeuses.

Peut-on définir une valeur par défaut lors de la déclaration d'une fonction, par exemple func F(a int = 10) ?

Non, il est impossible de déclarer une telle notation en Go - c'est uniquement une liste stricte des paramètres requis.

Que se passera-t-il si vous déclarez une fonction avec un slice de type ...interface{} et que vous lui passez 0 arguments ?

Le slice aura une longueur de 0 (nil), la fonction recevra un slice vide.

Exemple de code :

func PrintAll(args ...interface{}) { fmt.Println(len(args)) // 0 si aucun paramètre n'est passé } PrintAll() // ok

Peut-on surcharger (overload) des fonctions par nombre ou type de paramètres en Go ?

Non, la surcharge de fonctions en Go n'est pas supportée - les noms de fonction dupliqués avec des signatures différentes ne sont pas autorisés.

Erreurs typiques et anti-modèles

  • Essayer d'implémenter la surcharge via des interfaces variadiques ( ...interface{} ), en effectuant des vérifications de type complexes manuellement
  • Élargir excessivement l'API à des dizaines de paramètres - cela complique le soutien
  • Coder en dur des valeurs à l'intérieur des fonctions sans possibilité de configuration

Exemple de la vie réelle

Cas négatif

Une fonction API a des dizaines de paramètres, beaucoup d'entre eux ayant le même type, provoquant des erreurs à cause d'un mélange d'ordre :

Avantages :

  • Tout est clairement défini

Inconvénients :

  • Erreurs dues à des arguments vagues
  • Inconnu, quelles sont les valeurs par défaut

Cas positif

Une structure d'options ou des options fonctionnelles sont utilisées, les paramètres ont des noms explicites :

Avantages :

  • Signature flexible et extensible
  • Support des valeurs par défaut sans ambiguïté

Inconvénients :

  • Nécessite le soutien d'un "enrobage" supplémentaire (structures, fonctions d'options)