web-dev-qa-db-fra.com

Paramètres optionnels?

Go peut-il avoir des paramètres optionnels? Ou puis-je simplement définir deux fonctions avec le même nom et un nombre différent d'arguments?

387
devyn

Go n'a pas de paramètre optionnel il ne supporte pas non plus la surcharge de méthode :

L'envoi de méthode est simplifié s'il n'est pas nécessaire de faire la correspondance de type. L’expérience d’autres langues nous a appris qu’avoir recours à diverses méthodes du même nom mais avec des signatures différentes était parfois utile, mais que cela pouvait aussi être source de confusion et de fragilité dans la pratique. Faire correspondre uniquement par nom et nécessiter une cohérence dans les types était une décision de simplification majeure dans le système de types de Go.

374
Andrew Hare

Une méthode intéressante pour obtenir des paramètres facultatifs consiste à utiliser des arguments variadiques. La fonction reçoit en réalité une tranche du type que vous spécifiez.

func foo(params ...int) {
    fmt.Println(len(params))
}

func main() {
    foo()
    foo(1)
    foo(1,2,3)
}
187
Ferguzz

Vous pouvez utiliser une structure qui inclut les paramètres:

type Params struct {
  a, b, c int
}

func doIt(p Params) int {
  return p.a + p.b + p.c 
}

// you can call it without specifying all parameters
doIt(Params{a: 1, c: 9})
145
deamon

Pour un nombre arbitraire et potentiellement important de paramètres facultatifs, un idiome de Nice doit utiliser Options fonctionnelles .

Pour votre type Foobar, écrivez d'abord un seul constructeur:

func NewFoobar(options ...func(*Foobar) error) (*Foobar, error){
  fb := &Foobar{}
  // ... (write initializations with default values)...
  for _, op := range options{
    err := op(fb)
    if err != nil {
      return nil, err
    }
  }
  return fb, nil
}

où chaque option est une fonction qui mue le Foobar. Fournissez ensuite à votre utilisateur des moyens pratiques d’utiliser ou de créer des options standard, par exemple:

func OptionReadonlyFlag(fb *Foobar) error {
  fb.mutable = false
  return nil
}

func OptionTemperature(t Celsius) func(*Foobar) error {
  return func(fb *Foobar) error {
    fb.temperature = t
    return nil
  }
}

Terrain de je

Par souci de concision, vous pouvez nommer le type des options ( Playground ):

type OptionFoobar func(*Foobar) error

Si vous avez besoin de paramètres obligatoires, ajoutez-les en tant que premiers arguments du constructeur, avant la variable options.

Les principaux avantages de l'idiome des options fonctionnelles sont les suivants:

  • votre API peut évoluer dans le temps sans rompre le code existant, car la signature de constuctor reste la même lorsque de nouvelles options sont nécessaires.
  • cela permet au cas d'utilisation par défaut d'être le plus simple: pas d'argument du tout!
  • il fournit un contrôle précis sur l'initialisation de valeurs complexes.

Cette technique a été inventée par Rob Pike et également démontrée par Dave Cheney .

102
Deleplace

Ni les paramètres facultatifs ni la surcharge de fonctions ne sont pris en charge par Go. Go supporte un nombre variable de paramètres: Passage d'arguments à ... paramètres

16
peterSO

Non - ni Par le Go pour les programmeurs C++ docs,

Go ne prend pas en charge la surcharge de fonctions ni les opérateurs définis par l'utilisateur.

Je ne trouve pas d'affirmation tout aussi claire que les paramètres facultatifs ne sont pas pris en charge, mais ils ne le sont pas non plus.

5
Alex Martelli

Vous pouvez encapsuler cela assez bien dans une fonction similaire à celle décrite ci-dessous.

package main

import (
        "bufio"
        "fmt"
        "os"
)

func main() {
        fmt.Println(Prompt())
}

func Prompt(params ...string) string {
        Prompt := ": "
        if len(params) > 0 {
                Prompt = params[0]
        }
        reader := bufio.NewReader(os.Stdin)
        fmt.Print(Prompt)
        text, _ := reader.ReadString('\n')
        return text
}

Dans cet exemple, l'invite par défaut est précédée de deux points et d'un espace. . .

: 

. . . Cependant, vous pouvez le remplacer en fournissant un paramètre à la fonction Invite.

Prompt("Input here -> ")

Cela se traduira par une invite comme ci-dessous.

Input here ->
4
Jam Risser

Go language ne prend pas en charge la surcharge de méthodes, mais vous pouvez utiliser des arguments variadiques comme des paramètres facultatifs. Vous pouvez également utiliser l'interface {} comme paramètre, mais ce n'est pas un bon choix.

2
BaSO4

J'ai fini par utiliser une combinaison d'une structure de paramètres et d'arguments variadiques. De cette façon, je n'ai pas eu à changer l'interface existante utilisée par plusieurs services et mon service a pu transmettre des paramètres supplémentaires en fonction des besoins. Exemple de code dans la zone de jeux golang: https://play.golang.org/p/G668FA97N

2
Adriana

Je suis un peu en retard, mais si vous aimez l'interface fluide, vous pouvez concevoir vos paramètres pour les appels chaînés comme ceci:

type myType struct {
  s string
  a, b int
}

func New(s string, err *error) *myType {
  if s == "" {
    *err = errors.New(
      "Mandatory argument `s` must not be empty!")
  }
  return &myType{s: s}
}

func (this *myType) setA (a int, err *error) *myType {
  if *err == nil {
    if a == 42 {
      *err = errors.New("42 is not the answer!")
    } else {
      this.a = a
    }
  }
  return this
}

func (this *myType) setB (b int, _ *error) *myType {
  this.b = b
  return this
}

Et puis appelez ça comme ça:

func main() {
  var err error = nil
  instance :=
    New("hello", &err).
    setA(1, &err).
    setB(2, &err)

  if err != nil {
    fmt.Println("Failed: ", err)
  } else {
    fmt.Println(instance)
  }
}

Ceci est similaire au Options fonctionnelles présenté dans la réponse @Ripounet et bénéficie des mêmes avantages, mais présente certains inconvénients:

  1. Si une erreur se produit, elle n'abandonnera pas immédiatement. Par conséquent, il serait légèrement moins efficace de s'attendre à ce que votre constructeur rapporte souvent des erreurs.
  2. Vous devrez passer une ligne à déclarer une variable err et à la mettre à zéro.

Il y a cependant un petit avantage possible, ce type d'appels de fonction devrait être plus facile à intégrer pour le compilateur, mais je ne suis vraiment pas un spécialiste.

2
VinGarcia

Vous pouvez passer des paramètres nommés de manière arbitraire avec une carte.

type varArgs map[string]interface{}

func myFunc(args varArgs) {

    arg1 := "default" // optional default value
    if val, ok := args["arg1"]; ok {
        // value override or other action
        arg1 = val.(string) // runtime panic if wrong type
    }

    arg2 := 123 // optional default value
    if val, ok := args["arg2"]; ok {
        // value override or other action
        arg2 = val.(int) // runtime panic if wrong type
    }

    fmt.Println(arg1, arg2)
}

func Test_test() {
    myFunc(varArgs{"arg1": "value", "arg2": 1234})
}
1
nobar