Unerwartetes Anhängeverhalten bei Go-Slices: Eine Erklärung
In Go verhält sich die Append-Funktion beim Anhängen an ein Zeigersegment interessant. Um dies zu veranschaulichen, betrachten Sie den folgenden Code:
import "fmt" type Foo struct { val int } func main() { var a = make([]*Foo, 1) a[0] = &Foo{0} var b = [3]Foo{Foo{1}, Foo{2}, Foo{3}} for _, e := range b { a = append(a, &e) } for _, e := range a { fmt.Printf("%v ", *e) } }
Entgegen der Erwartung, dass der Code {0} {1} {2} {3} ausgeben würde, gibt er stattdessen {0} {3} { aus. 3} {3}. Der Grund für diese Diskrepanz liegt in der Natur der Bereichsvariablen der for-Schleife.
Die Bereichsvariable verstehen
Die for-range-Schleife in Go erstellt eine Kopie jedes Elements im Array oder Slice, über das iteriert wird. In diesem Fall ist e eine Kopie des Elements im Array b. Daher ist e selbst nicht das Element in b; Vielmehr handelt es sich um eine temporäre Variable, die den Wert des Elements enthält.
Beim Anhängen an das Segment a hängt der Code die Adresse von e an, nicht die Adresse des tatsächlichen Elements in b. Da e für alle Iterationen dieselbe Kopie ist, wird derselbe Zeiger dreimal an a angehängt. Somit ist der letzte Wert, der e zugewiesen ist (das ist Foo{3}), derjenige, der wiederholt gedruckt wird.
Beheben des Verhaltens
Um dieses Verhalten zu beheben, verwenden Sie den Code sollte die Adresse des tatsächlichen Elements in b anhängen, nicht die Adresse von e. Die korrigierte Schleife würde so aussehen:
for i := range b { a = append(a, &b[i]) }
Durch das Anhängen von &b[i] anstelle von &e stellt der Code sicher, dass jedes Element in b zu a hinzugefügt wird. Folglich wird die korrekte Ausgabe {0} {1} {2} {3} gedruckt.
Grund für das anfängliche Verhalten
Dieses unerwartete Verhalten ist auf die Abwesenheit zurückzuführen der wahren Referenzen in Go. Go verfügt über Zeigertypen und Nicht-Zeigertypen, aber keine Referenzen. Die Bereichsvariable ist einfach eine lokale Variable, die einen Wert enthält, der ein Zeiger oder ein Nicht-Zeiger sein kann. Es kann keine Referenz enthalten.
Daher manipuliert man bei der Bearbeitung der Bereichsvariablen nur den Wert, nicht das Element selbst. Um das tatsächliche Element zu ändern, muss man den Wert der Bereichsvariablen zuweisen und so den Wert effektiv kopieren. Dieser Wert wird dann in der nächsten Iteration überschrieben.
Das obige ist der detaillierte Inhalt vonWarum führt die Append-Funktion von Go zu unerwarteten Ergebnissen, wenn Zeiger aus einer for-range-Schleife angehängt werden?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!