web-dev-qa-db-fra.com

Comment définir les valeurs par défaut dans les structures Go

Il y a plusieurs réponses/techniques à la question ci-dessous:

  1. Comment définir les valeurs par défaut pour les structures golang?
  2. Comment initialiser les structures dans golang

J'ai quelques réponses mais une discussion plus approfondie est nécessaire.

103
Prateek
  1. Forcer une méthode pour obtenir la structure (à l'aide du constructeur).

    Une bonne conception consiste à rendre votre type non exporté, mais à fournir une fonction de constructeur exportée telle que NewMyType () dans laquelle vous pouvez initialiser correctement votre structure/type. Renvoyez également un type d'interface et non un type concret. L'interface doit contenir tout ce que les autres veulent faire avec votre valeur. Et votre type concret doit bien sûr implémenter cette interface.

    Cela peut être fait simplement en rendant le type non exporté. Vous pouvez exporter la fonction NewSomething et même les champs Text et DefaultText, mais n'exportez simplement pas le type struct.

  2. Une autre façon de le personnaliser pour votre propre module consiste à utiliser une structure de configuration pour définir les valeurs par défaut (Option 5 dans le lien). Ce n'est cependant pas un bon moyen.

47
Prateek

Une idée possible est d’écrire une fonction constructeur séparée

//Something is the structure we work with
type Something struct {
     Text string 
     DefaultText string 
} 
// NewSomething create new instance of Something
func NewSomething(text string) Something {
   something := Something{}
   something.Text = text
   something.DefaultText = "default text"
   return something
}
72
vodolaz095

Un problème avec l’option 1 dans la réponse de Victor Zamanian est que si le type n’est pas exporté, les utilisateurs de votre paquet ne peuvent pas le déclarer comme type pour les paramètres de fonction, etc. Un moyen de contourner ce problème serait d’exporter une interface struct par exemple.

package candidate
// Exporting interface instead of struct
type Candidate interface {}
// Struct is not exported
type candidate struct {
    Name string
    Votes unit32 // Defaults to 0
}
// We are forced to call the constructor to get an instance of candidate
func New(name string) Candidate {
    return candidate{name, 0}  // enforce the default value here
}

Ce qui nous permet de déclarer les types de paramètres de fonction à l'aide de l'interface candidate exportée. Le seul inconvénient de cette solution est que toutes nos méthodes doivent être déclarées dans la définition d'interface, mais vous pouvez dire que c'est néanmoins une bonne pratique.

20
wolfson109

Il existe un moyen de le faire avec des balises, ce qui permet de définir plusieurs valeurs par défaut.

Supposons que vous ayez la structure suivante, avec 2 balises par défaut default0 et default1 .

type A struct {
   I int    `default0:"3" default1:"42"`
   S string `default0:"Some String..." default1:"Some Other String..."`
}

Il est maintenant possible de définir les valeurs par défaut.

func main() {

ptr := &A{}

Set(ptr, "default0")
fmt.Printf("ptr.I=%d ptr.S=%s\n", ptr.I, ptr.S)
// ptr.I=3 ptr.S=Some String...

Set(ptr, "default1")
fmt.Printf("ptr.I=%d ptr.S=%s\n", ptr.I, ptr.S)
// ptr.I=42 ptr.S=Some Other String...
}

Voici le programme complet dans une cour de récréation .

Si vous êtes intéressé par un exemple plus complexe, par exemple avec des tranches et des cartes, jetez un oeil à creasty/defaultse

3
Mike Chirico

De https://golang.org/doc/effective_go.html#composite_literals :

Parfois, la valeur zéro n'est pas assez bonne et un constructeur d'initialisation est nécessaire, comme dans cet exemple dérivé de package os.

    func NewFile(fd int, name string) *File {
      if fd < 0 {
        return nil
      }
      f := new(File)
      f.fd = fd
      f.name = name
      f.dirinfo = nil
      f.nepipe = 0
      return f
}
2
RdB
type Config struct {
    AWSRegion                               string `default:"us-west-2"`
}
1
user10209901