Le paramètre ...T
Placez ... devant le type du dernier paramètre. Les appelants peuvent alors passer un nombre quelconque d'arguments de ce type, y compris aucun. Dans la fonction, le paramètre est une slice.
Ce code affiche 0, 5 et 10. Sans argument, nums est une slice nil de longueur 0, donc la boucle ne s'exécute tout simplement pas.
Des paramètres ordinaires peuvent venir avant. Seul le dernier peut être variadique :
func logf(level string, format string, args ...any)
Passer une slice avec s...
Si vous avez déjà une slice, vous ne pouvez pas la passer directement : sum(nums) échoue avec cannot use nums (variable of type []int) as int value in argument to sum. Développez-la avec ... après l'argument :
append est aussi variadique, c'est pourquoi joindre deux slices s'écrit append(a, b...).
L'expansion doit être la seule chose à la position variadique. sum(1, nums...) échoue avec too many arguments in call to sum. Construisez d'abord la slice combinée avec append.
La slice est partagée, pas copiée
Quand vous appelez avec des arguments individuels, Go crée une nouvelle slice pour eux. Quand vous développez une slice existante avec s..., la fonction reçoit cette même slice. Écrire dans ses éléments modifie les données de l'appelant.
Sortie :
[7 8 9]
[0 8 9]
Une fonction variadique qui modifie son paramètre devrait le documenter, ou copier d'abord avec slices.Clone. La plupart des fonctions variadiques ne font que lire leurs arguments, donc cela piège rarement, mais c'est une vraie différence avec les langages où les paramètres rest sont toujours un nouveau tableau.
...any et le fonctionnement de fmt.Println
fmt.Println est déclarée func Println(a ...any) (n int, err error). any (un alias de interface{} depuis Go 1.18) accepte tous les types, donc vous pouvez passer des chaînes, des nombres et des structs dans un même appel.
La transmission est le détail important : logf passe args... à Printf. Sans les points, Printf reçoit un seul argument, un []any, et la ligne d'avertissement affiche [WARN] [3 8] of %!d(MISSING) workers idle. go vet ne signale missing ... in args forwarded to printf-like function que lorsque le paramètre de format est transmis tel quel, comme dans fmt.Printf(format, args). Ici le format est construit avec +, donc vet reste silencieux et les points sont à votre charge.
Une []string ne peut pas être développée dans un ...any. Les types des éléments doivent correspondre exactement, donc convertissez d'abord :
names := []string{"a", "b"}
args := make([]any, len(names))
for i, n := range names {
args[i] = n
}
fmt.Println(args...)
Exiger au moins un argument
Un paramètre variadique accepte zéro argument. Quand la fonction en a besoin d'au moins un, faites du premier un paramètre ordinaire :
maxOf() devient alors une erreur de compilation au lieu d'une vérification à l'exécution. La fonction intégrée max fonctionne de la même façon : elle exige au moins un argument.
Les paramètres variadiques comme arguments facultatifs
Go n'a pas de valeurs de paramètre par défaut. Un paramètre variadique sert parfois à simuler un argument facultatif :
func connect(addr string, timeout ...time.Duration)
Cela fonctionne mais se lit mal, puisque les appelants peuvent passer trois timeouts et que la signature ne dit pas lequel l'emporte. Pour plus d'une option, préférez une struct de configuration, ou le motif des options fonctionnelles (...Option, où chaque Option est une fonction qui définit un champ). Ce motif est variadique, mais chaque argument a un sens clair.
Référence des règles
| Règle | Exemple |
|---|---|
| Seul le dernier paramètre peut être variadique | func f(a string, b ...int) |
| Dans la fonction, le paramètre est une slice | b a le type []int |
| Zéro argument donne une slice nil | f("x") donne b == nil |
Développer une slice avec ... | f("x", nums...) |
| L'expansion partage le tableau sous-jacent | écrire dans b[i] modifie nums |
| Pas de mélange entre expansion et valeurs supplémentaires | f("x", 1, nums...) ne compile pas |
Questions fréquentes
Qu'est-ce qu'une fonction variadique en Go ?
Une fonction dont le dernier paramètre a la forme ...T, comme func sum(nums ...int) int. On peut l'appeler avec zéro argument ou plus de type T, et dans la fonction le paramètre est une slice []T.
Comment passer une slice à une fonction variadique en Go ?
Ajoutez ... après la slice : sum(nums...). La slice est passée telle quelle, sans copie, donc la fonction voit le même tableau sous-jacent. Vous ne pouvez pas mélanger l'expansion et des arguments individuels : sum(1, nums...) ne compile pas.
Go a-t-il un opérateur spread ?
Seulement pour le dernier argument d'un appel variadique : f(s...). Il n'existe pas d'expansion générale pour construire des tableaux ou des structs, ni pour appeler des fonctions non variadiques avec une slice. append(a, b...) est la même règle appliquée à la fonction intégrée append.
Une fonction Go peut-elle avoir deux paramètres variadiques ?
Non. Seul le dernier paramètre peut être variadique, et il n'y en a qu'un par fonction. Passez les listes supplémentaires comme paramètres slice ordinaires.