Wenn Sie eine Variable deklarieren, wo T
ist irgendeine Art:
var name T
Gehen Sie ein Stück nicht initialisierten gibt „genullt“ Gedächtnis.
Mit Primitiven bedeutet dies, var name int
wäre 0, und var name string
wäre "". In C it might be zeroed, or might be something unexpected. Go garantiert, dass eine nicht initialisierte Variable das Null-Äquivalent des Typs ist.
Interne Slices, Karten und Kanäle werden als Zeiger behandelt. Zeiger Nullwert ist Null, was bedeutet, dass er auf Null Speicher zeigt. Ohne es zu initialisieren, können Sie eine Panik bekommen, wenn Sie versuchen, darauf zu operieren.
Die Funktion make
wurde speziell für einen Schnitt, eine Karte oder einen Kanal entwickelt. Die Argumente der Schliesser sind:
make(T type, length int[, capacity int]) // For slices.
make(T[, capacity int]) // For a map.
make(T[, bufferSize int]) // For a channel. How many items can you take without blocking?
A Scheiben length
ist, wie viele Elemente es beginnt mit. Die Kapazität ist der zugewiesene Speicher, bevor eine Größenänderung erforderlich ist (intern, neue Größe * 2, dann kopieren). Weitere Informationen finden Sie unter Effective Go: Allocation with make.
Struktur: new(T)
entspricht &T{}
, nicht T{}
. *new(T)
entspricht *&T{}
.
Scheiben: make([]T,0)
entspricht []T{}
.
Karten: make(map[T]T)
entspricht map[T]T{}
.
Soweit die Methode bevorzugt wird, frage ich mich, die folgende Frage:
Kenne ich den Wert (e) jetzt in der Funktion?
Wenn die Antwort "Ja" ist, dann gehe ich mit einem der oben genannten T{...}
. Wenn die Antwort "Nein" ist, verwende ich make oder new.
Zum Beispiel würde ich so etwas wie dies vermeiden:
type Name struct {
FirstName string
LastName string
}
func main() {
name := &Name{FirstName:"John"}
// other code...
name.LastName = "Doe"
}
Stattdessen würde ich so etwas tun:
func main() {
name := new(Name)
name.FirstName = "John"
// other code...
name.LastName = "Doe"
}
Warum? Denn mit new(Name)
mache ich klar, dass ich beabsichtige, um die Werte später zu füllen. Wenn ich verwenden würde, wäre es nicht klar, dass ich beabsichtigte, einen Wert später in derselben Funktion hinzuzufügen/zu ändern, ohne den Rest des Codes zu lesen.
Die Ausnahme ist mit Strukturen, wenn Sie keinen Zeiger wollen. Ich werde T{}
verwenden, aber ich werde nichts hinzufügen, wenn ich die Werte hinzufügen/ändern möchte. Natürlich funktioniert auch *new(T)
, aber das ist wie mit *&T{}
. T{}
ist sauberer in diesem Fall, obwohl ich dazu neige, Zeiger mit Strukturen zu verwenden, um eine Kopie zu vermeiden, wenn ich sie herumließe.
Eine andere Sache zu beachten, eine []*struct
ist kleiner und billiger zu resize als []struct
, unter der Annahme, die Struktur ist viel größer als ein Zeiger, der in der Regel 4 - 8 Bytes ist (8 Bytes auf 64bit?).
+1 Beantwortet die Frage nicht wirklich, aber ich bin mir sicher - ich bin froh zu wissen, dass Pike es selbst gesagt hat. Das ist eine Schwäche, die ich bei GoLang finde: Zu viele Möglichkeiten, die Vor- und Nachteile und die Angemessenheit von ihnen zu deklarieren und nicht zu klären - das gibt mir manchmal eine Art "nicht ganz fertig". – Vector