Wann erstellt Golang append() ein neues Slice?
Die Dokumentation für append() gibt an, dass ein neues Slice zugewiesen wird und Kopieren Sie die Elemente, wenn die Kapazität des ursprünglichen Slice nicht ausreicht. Bei der Untersuchung der Ausgabe des folgenden Codes, der Kombinationen eines booleschen Alphabets generiert, tritt jedoch eine Diskrepanz auf.
<code class="go">package main import ( "fmt" ) func AddOption(c chan []bool, combo []bool, length int) { if length == 0 { fmt.Println(combo, "!") c <- combo return } var newCombo []bool for _, ch := range []bool{true, false} { newCombo = append(combo, ch) AddOption(c, newCombo, length-1) } } func main() { c := make(chan []bool) go func(c chan []bool) { defer close(c) AddOption(c, []bool{}, 4) }(c) for combination := range c { fmt.Println(combination) } }</code>
Kontrastierende Beobachtungen
In der Ausgabe wird die Zeilen, die mit einem Ausrufezeichen enden, stellen Slices dar, die von AddOption über den Kanal gesendet werden, während die Zeilen ohne Ausrufezeichen die in main() empfangenen Slices anzeigen. Bemerkenswerterweise scheinen die über den Kanal gesendeten Slices nach dem Senden geändert zu werden, obwohl append() angeblich ein neues Slice zurückgibt.
Untersuchung der Quelle
Der fragwürdige Codeblock ist:
<code class="go">var newCombo []bool for _, ch := range []bool{true, false} { newCombo = append(combo, ch) AddOption(c, newCombo, length-1) }</code>
Laut Dokumentation sollte append() einen neuen Slice-Deskriptor zurückgeben, der auf ein neues zugrunde liegendes Datenarray zeigt, wenn die Kapazität des ursprünglichen Slice nicht ausreicht. Der als zweites Argument an AddOption übergebene Wert kann jedoch entweder ein Zeiger auf einen Slice-Deskriptor oder eine echte Kopie des Slice-Deskriptors sein.
Klarstellung des Verhaltens
Die Antwort auf diese Frage liegt in der Unterscheidung zwischen dem Slice-Datentyp und seiner tatsächlichen Darstellung. Ein Slice-Deskriptor besteht aus zwei Ganzzahlen für Länge und Kapazität sowie einem Zeiger auf die zugrunde liegenden Daten.
Append() gibt zwar einen neuen Slice-Deskriptor mit einem möglicherweise anderen zugrunde liegenden Datenarray zurück, dem Zeiger auf die Daten bleibt gleich, sofern die Kapazität nicht erweitert wird. Dies bedeutet, dass der Slice-Deskriptor selbst zwar eine Kopie ist, der Zeigerwert (Adresse auf die zugrunde liegenden Daten) jedoch gemeinsam genutzt wird.
Zusätzliches Beispiel
Bedenken Sie dies zur Veranschaulichung Codeausschnitt:
<code class="go">package main import "fmt" func main() { s := make([]int, 0, 5) s = append(s, []int{1, 2, 3, 4}...) a := append(s, 5) fmt.Println(a) b := append(s, 6) fmt.Println(b) fmt.Println(a) }</code>
Dieser Code gibt Folgendes aus:
[1 2 3 4 5] [1 2 3 4 6] [1 2 3 4 6]
Anfangs verfügt s über genügend Kapazität, sodass a und b denselben zugrunde liegenden Datenzeiger verwenden. Wenn wir jedoch die Kapazität von s auf 4 reduzieren, ändert sich die Ausgabe wie folgt:
[1 2 3 4 5] [1 2 3 4 6] [1 2 3 4 5]
Dies zeigt, dass a und b nur dann dieselben zugrunde liegenden Daten teilen, wenn s über ausreichende Kapazität verfügt.
Das obige ist der detaillierte Inhalt vonWarum scheint „append()' von Golang ein Slice zu ändern, nachdem es über einen Kanal gesendet wurde?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!