Heim > Backend-Entwicklung > Golang > Warum verändert das Anhängen an eine Kopie eines Go-Slices auch das Original-Slice?

Warum verändert das Anhängen an eine Kopie eines Go-Slices auch das Original-Slice?

Patricia Arquette
Freigeben: 2024-11-20 14:53:14
Original
632 Leute haben es durchsucht

Why does appending to a copy of a Go slice also modify the original slice?

Das Anhängen von Slice und seine Auswirkung auf das ursprüngliche Slice verstehen

Beim Arbeiten mit Slices in Go wird die Append-Funktion häufig zum Anhängen neuer Elemente verwendet zu einem vorhandenen Slice. Viele Entwickler werden jedoch überrascht sein, wenn sie feststellen, dass dieser Anhängevorgang auch das Original-Slice ändern kann.

Der untersuchte Code

Bedenken Sie den folgenden Codeausschnitt:

func someFunc(A []int) int {
    for i := 0; i < len(A); i++ {
        tempA := A // copy the slice by value

        fmt.Println("A: ", A)
        fmt.Println("tempA: ", A)
        fmt.Println()

        newArr = remove(tempA, i)

        if isAesthetic(newArr) {
            ways++
        }
    }
}

func remove(slice []int, s int) []int {
    return append(slice[:s], slice[s+1:]...)
}
Nach dem Login kopieren

Hier nimmt die someFunc-Funktion ein Slice A als Eingabe und erstellt dann eine Kopie von A namens tempA, bevor sie die aufruft Remove-Funktion zum Entfernen eines Elements aus tempA. Wenn Sie die Funktion in Aktion untersuchen, bemerken Sie möglicherweise die folgende Konsolenausgabe:

A:  [3 4 5 3 7]
tempA:  [3 4 5 3 7]

A:  [4 5 3 7 7]
tempA:  [4 5 3 7 7]

A:  [4 3 7 7 7]
tempA:  [4 3 7 7 7]

A:  [4 3 7 7 7]
tempA:  [4 3 7 7 7]
Nach dem Login kopieren

Der überraschende Nebeneffekt

Während der Code ausgeführt wird, wird der Inhalt von gedruckt Sowohl A als auch tempA, was zeigt, dass der ursprüngliche Slice A ebenfalls geändert wird, nachdem append für tempA aufgerufen wurde. Dieses Verhalten mag auf den ersten Blick kontraintuitiv erscheinen, da man erwarten würde, dass eine By-Value-Kopie von A unabhängig von allen an tempA vorgenommenen Änderungen ist.

Dieses Phänomen ist jedoch eine direkte Folge der Art und Weise, wie Slices implementiert werden in Go. Slices sind im Wesentlichen eine leichtgewichtige Datenstruktur, die aus einem Header und einem Zeiger auf das zugrunde liegende Array besteht. Der Header enthält Informationen über die Länge und Kapazität des Slice, während der Zeiger auf das erste Element im Slice zeigt.

Wenn Sie tempA den Wert von A zuweisen, erstellen Sie im Wesentlichen einen neuen Slice-Header, der auf zeigt das gleiche zugrunde liegende Array wie A. Daher werden alle an tempA vorgenommenen Änderungen auch in A widergespiegelt, da beide Slices auf dieselben Daten verweisen.

Slice verstehen Header und Arrays

Um dieses Verhalten besser zu verstehen, ist es hilfreich zu verstehen, wie Slice-Header und Arrays in Go interagieren. Ein Array enthält einen zusammenhängenden Block von Elementen desselben Typs. Ein Slice hingegen bietet eine dynamische Ansicht eines Abschnitts des Arrays. Es beschreibt einen aufeinanderfolgenden Satz von Elementen innerhalb des Arrays, besitzt aber nicht die zugrunde liegenden Array-Daten.

Wenn Sie ein Slice aus einem Array mit der Syntax []T{e1, e2, ... erstellen, en} erstellen Sie im Wesentlichen einen neuen Slice-Header, der auf das erste Element im Array zeigt. Die Länge des Slice wird auf n und die Kapazität auf die verbleibende Länge des Arrays nach dem Slice festgelegt.

Ähnlich gilt, wenn Sie einen Slice-Header mit der Syntax []T(arr) erstellen, Sie erstellen ein Slice, das auf dasselbe zugrunde liegende Array wie arr verweist. Die Länge des Slice wird auf die Länge von arr und die Kapazität auf die Kapazität von arr eingestellt.

Implikationen und Best Practices

Wenn Sie die Beziehung zwischen Slices und Arrays verstehen, können Sie potenzielle Fallstricke vermeiden und effizienteren Go-Code schreiben. Beachten Sie beim Arbeiten mit Slices Folgendes:

  • Vermeiden Sie die Zuweisung eines Slice zu einem anderen Slice, wenn Sie unabhängige Referenzen auf dasselbe zugrunde liegende Array beibehalten möchten.
  • Verwenden Sie copy(dst , src), um ein neues Slice mit einem anderen Header zu erstellen und dabei auf dasselbe zugrunde liegende Array zu verweisen.
  • Erwägen Sie die Verwendung der make-Funktion, um ein Slice mit a zu erstellen spezifische Länge und Kapazität, wodurch der Aufwand für die potenzielle Zuweisung und das Kopieren eines neuen zugrunde liegenden Arrays vermieden wird.

Wenn Sie die Interna von Go-Slices verstehen, können Sie deren Flexibilität und Effizienz nutzen und gleichzeitig sicherstellen, dass sich Ihr Code wie beabsichtigt verhält. Indem Sie die Nuancen von Slice-Headern und -Arrays nutzen, können Sie die Kunst des Slicings in Go meistern und das volle Potenzial dieser vielseitigen Datenstruktur ausschöpfen.

Das obige ist der detaillierte Inhalt vonWarum verändert das Anhängen an eine Kopie eines Go-Slices auch das Original-Slice?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:php.cn
Erklärung dieser Website
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
Neueste Artikel des Autors
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage