J'ai une structure et j'aimerais qu'elle soit initialisée avec des valeurs par défaut sensibles.
Généralement, la chose à faire est d'utiliser un constructeur, mais puisque go n'est pas vraiment OOP au sens traditionnel, ce ne sont pas de vrais objets et il n'a pas de constructeur.
J'ai remarqué la méthode init mais c'est au niveau du paquet. Y a-t-il autre chose de semblable qui peut être utilisé au niveau de la structure?
Si non, quelle est la meilleure pratique acceptée pour ce type de choses dans Go?
Il existe actuellement deux meilleures pratiques acceptées:
func New() YourTyp
ou, si votre paquet contient plusieurs types de ce type, func NewYourType1() YourType1
et ainsi de suite.Documentez si une valeur nulle de votre type est utilisable ou non (dans ce cas, elle doit être configurée par l'une des fonctions New...
. (Pour les "traditionalistes" oups: Quelqu'un qui ne lit pas la documentation gagnée ' t être capable d’utiliser vos types correctement, même s’il ne peut pas créer d’objets dans des états non définis.)
Il existe des équivalents de constructeurs pour les cas où les valeurs zéro ne peuvent pas définir de valeurs par défaut raisonnables ou pour certains paramètres nécessaires à l'initialisation de la structure.
En supposant que vous ayez une structure comme celle-ci:
type Thing struct {
Name string
Num int
}
ensuite, si les valeurs zéro ne correspondent pas, vous construirez généralement une instance avec une fonction NewThing
renvoyant un pointeur:
func NewThing(someParameter string) *Thing {
p := new(Thing)
p.Name = someParameter
p.Num = 33 // <- a very sensible default value
return p
}
Lorsque votre structure est assez simple, vous pouvez utiliser cette construction condensée:
func NewThing(someParameter string) *Thing {
return &Thing{someParameter, 33}
}
Si vous ne voulez pas renvoyer de pointeur, il est alors nécessaire d'appeler la fonction makeThing
au lieu de NewThing
:
func makeThing(name string) Thing {
return Thing{name, 33}
}
Référence: Allocation avec nouveau dans Effective Go .
Allez a des objets. Les objets peuvent avoir des constructeurs (mais pas des constructeurs automatiques). Enfin, Go est un langage OOP (les types de données sont associés à des méthodes, mais il existe certes de nombreuses définitions de ce que OOP est.)
Néanmoins, la meilleure pratique acceptée consiste à écrire zéro ou plusieurs constructeurs pour vos types.
Comme @dystroy a posté sa réponse avant que je termine cette réponse, permettez-moi d'ajouter une version alternative de son exemple de constructeur, que j'écrirais probablement à la place:
func NewThing(someParameter string) *Thing {
return &Thing{someParameter, 33} // <- 33: a very sensible default value
}
La raison pour laquelle je veux vous montrer cette version est que très souvent, des littéraux "en ligne" peuvent être utilisés à la place d'un appel "constructeur".
a := NewThing("foo")
b := &Thing{"foo", 33}
Maintenant, *a == *b
.
Il n'y a pas de constructeurs par défaut dans Go, mais vous pouvez déclarer des méthodes pour n'importe quel type. Vous pourriez prendre l’habitude de déclarer une méthode appelée "Init". Je ne sais pas si cela est lié aux meilleures pratiques, mais cela aide à garder les noms courts sans perdre la clarté.
package main
import "fmt"
type Thing struct {
Name string
Num int
}
func (t *Thing) Init(name string, num int) {
t.Name = name
t.Num = num
}
func main() {
t := new(Thing)
t.Init("Hello", 5)
fmt.Printf("%s: %d\n", t.Name, t.Num)
}
Le résultat est:
Hello: 5
J'aime l'explication de ceci blog post :
La fonction New est une convention Go pour les packages qui créent un type de base ou différents types à utiliser par le développeur de l'application. Regardez comment New est défini et implémenté dans log.go, bufio.go et cypto.go:
// New creates a new Logger. The out variable sets the
// destination to which log data will be written.
// The prefix appears at the beginning of each generated log line.
// The flag argument defines the logging properties.
func New(out io.Writer, prefix string, flag int) * Logger {
return &Logger{out: out, prefix: prefix, flag: flag}
}
// NewReader returns a new Reader whose buffer has the default size.
func NewReader(rd io.Reader) * Reader {
return NewReaderSize(rd, defaultBufSize)
}
// New returns a new hash.Hash calculating the given hash function. New panics
// if the hash function is not linked into the binary.
func (h Hash) New() hash.Hash {
if h > 0 && h < maxHash {
f := hashes[h]
if f != nil {
return f()
}
}
panic("crypto: requested hash function is unavailable")
}
Étant donné que chaque package agit comme un espace de noms, chaque package peut avoir sa propre version de New. Dans bufio.go, vous pouvez créer plusieurs types, il n’existe donc pas de nouvelle fonction autonome. Ici vous trouverez des fonctions comme NewReader et NewWriter.
une autre façon est;
package person
type Person struct {
Name string
Old int
}
func New(name string, old int) *Person {
// set only specific field value with field key
return &Person{
Name: name,
}
}
Si vous voulez forcer l'utilisation de la fonction factory, nommez votre structure (votre classe) avec le premier caractère en minuscule. Ensuite, il ne sera pas possible d’instancier directement la structure, la méthode fabrique sera requise.
Cette visibilité basée sur les lettres majuscules/minuscules du premier caractère fonctionne également pour le champ struct et pour la fonction/méthode. Si vous ne souhaitez pas autoriser l'accès externe, utilisez des minuscules.
Golang n’est pas OOP dans ses documents officiels. Tous les champs de la structure de Golang ont une valeur déterminée (contrairement à c/c ++), la fonction constructeur n’est donc pas aussi nécessaire que cpp. Si vous devez affecter des valeurs spéciales à certains champs, utilisez les fonctions d'usine. La communauté de Golang suggère New .. noms de modèles.