Il y a plusieurs réponses/techniques à la question ci-dessous:
J'ai quelques réponses mais une discussion plus approfondie est nécessaire.
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.
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.
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
}
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.
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
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
}
type Config struct {
AWSRegion string `default:"us-west-2"`
}