Heim >Backend-Entwicklung >Golang >Warum scheint „append()' von Golang ein Slice zu ändern, nachdem es über einen Kanal gesendet wurde?

Warum scheint „append()' von Golang ein Slice zu ändern, nachdem es über einen Kanal gesendet wurde?

Linda Hamilton
Linda HamiltonOriginal
2024-11-02 10:01:31352Durchsuche

Why Does Golang's `append()` Seem to Modify a Slice After It's Sent Over a Channel?

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!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn