Unerwartetes Slice-Anhängeverhalten in Go
Im Bereich der Go-Programmierung ist beim Anhängen von Elementen an ein darin enthaltenes Slice ein ungewöhnliches Verhalten aufgetreten eine Schleife und versucht anschließend, basierend auf dem Ergebnis der Schleife neue Slices zu erstellen. Interessanterweise überschreibt der letzte Anhängevorgang die Slices, die aus vorherigen Anhängen erstellt wurden.
Untersuchung des Problems
Bedenken Sie den folgenden Codeausschnitt:
<code class="go">func create(iterations int) []int { a := make([]int, 0) for i := 0; i < iterations; i++ { a = append(a, i) } return a }</code>
Beim Aufruf von create(11) und beim Erstellen neuer Slices durch Anhängen von Elementen (d. h. j := append(i, 100), g := append(i, 101), h := append(i, 102)), eins würde erwarten, dass die letzten Elemente dieser Slices (j, g und h) 100, 101 bzw. 102 sind. Überraschenderweise sind in diesem Fall jedoch alle 102.
Dieses Verhalten steht in krassem Gegensatz zu dem, was passiert, wenn neue Slices aus einem Slice-Literal erstellt werden, wie unten gezeigt:
<code class="go">func sliceFromLiteral() { i := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10} j := append(i, 100) g := append(i, 101) h := append(i, 102) fmt.Printf("i: %v\nj: %v\ng: %v\nh:%v\n", i, j, g, h) }</code>
In diesem Fall zeigen j, g und h das erwartete Verhalten, wobei die letzten Elemente 100, 101 bzw. 102 sind.
Eintauchen in die Grundursache
Um das Geheimnis hinter diesem unerwarteten Verhalten zu lüften, ist es wichtig zu verstehen, dass der Anhängevorgang nicht nur das zugrunde liegende Array ändert, sondern auch ein neues Slice zurückgibt. Dies impliziert, dass die Slices j, g und h tatsächlich auf dasselbe zugrunde liegende Array verweisen. Wenn also das letzte Anhängen (append(i, 102)) ausgeführt wird, ändert es das letzte Element des zugrunde liegenden Arrays und überschreibt effektiv die Werte in j, g und h.
The Idiomatic Lösung
Um dieses unerwartete Verhalten zu vermeiden, ist es unbedingt erforderlich, das Slice zu kopieren, bevor Sie versuchen, etwas anzuhängen. Dadurch wird ein neues zugrunde liegendes Array erstellt und sichergestellt, dass der ursprüngliche Slice unverändert bleibt. Der folgende Code veranschaulicht die idiomatische Art und Weise, mehrere neue Slices basierend auf vorhandenen zu erstellen:
<code class="go">func makeFromSlice(sl []int) []int { result := make([]int, len(sl)) copy(result, sl) return result }</code>
Mit diesem Ansatz kann man mühelos neue Slices erstellen und gleichzeitig die Integrität der Originaldaten bewahren.
Die Slice-Literal-Ausnahme
Das besondere Verhalten, das bei aus Schleifen erstellten Slices beobachtet wird, erstreckt sich nicht auf Slices, die aus Literalen initialisiert werden. Dies ist darauf zurückzuführen, dass Go ein neues Array zuweist, wenn eine Anhängeoperation die Kapazität des Hintergrundarrays überschreiten würde. Dieses Verhalten ist unabhängig davon, ob das Slice aus einem Literal oder einer Variablen erstellt wird, und ist lediglich eine Folge davon, wie Arrays intern in Go behandelt werden.
Das obige ist der detaillierte Inhalt vonWarum zeigen in einer Schleife angehängte Slices beim Erstellen neuer Slices in Go ein unerwartetes Verhalten?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!