Historie der Frage:
Go wurde als Sprache mit expliziter Value-Semantik entworfen: Fast alles wird beim Übergeben durch Wert kopiert, einschließlich Strukturen (struct), jedoch nicht Zeiger und nicht Slices (slice). Dies vereinfachte das Reasoning und erhöhte die Sicherheit, brachte jedoch eine Reihe von "Fallen" mit sich.
Problem:
Oft erwarten Entwickler, dass bei der Übergabe einer Struktur an eine Funktion ihre Änderungen auch "nach außen" sichtbar sind. Es findet jedoch eine Kopie des gesamten Inhalts statt (einschließlich der eingebetteten Felder — durch Wert!). Für Slices und Maps gilt ein anderes Verhalten, bei dem der "Container" kopiert wird, jedoch nicht der "Inhalt".
Lösung:
Übergeben Sie große Strukturen per Zeiger, wenn eine Änderung erwartet wird. Bei Slices wird nur der Deskriptor (Länge, Kapazität, Zeiger) kopiert und nicht der Inhalt — Änderungen des ursprünglichen Slices (über den Index) sind extern sichtbar. Bei Structs wird alles kopiert:
type Point struct { X, Y int } func move(p Point) { p.X = 100 } func movePtr(p *Point) { p.X = 100 } func demo() { pt := Point{10, 10} move(pt) fmt.Println(pt.X) // 10 movePtr(&pt) fmt.Println(pt.X) // 100 }
Wesentliche Merkmale:
Wenn die Struktur innerhalb der Funktion geändert wird, ändert sich das Original?
Nein, wenn die Struktur durch Wert übergeben wird — die Änderungen sind lokal.
type User struct {Name string} func f(u User) {u.Name = "Ann"}
Wenn ein Element des Slices innerhalb der Funktion geändert wird, ändert sich das Original?
Ja. Slices sind eine "Ansicht" auf ein gemeinsames Array. Wenn Sie ein Element ändern, ändern Sie auch die ursprünglichen Daten.
func f(s []int) {s[0] = 99}
Was passiert, wenn ein Slice zurückgegeben wird, das innerhalb der Funktion erstellt wurde?
Der "Kopf" des Slices wird kopiert, aber das zugrunde liegende Array bleibt zugänglich. Wenn kein Verweis nach außen gespeichert wird, können die Daten vom GC gesammelt werden.
In der Funktion wurde die Struktur User durch Wert verarbeitet — Änderungen gelangten nicht zurück, Bugs sind schwer zu finden.
Vorteile:
Nachteile:
Große Strukturen werden eindeutig per Zeiger übergeben, und für Slices wird immer das Verhalten kommentiert oder überprüft. Es gibt keine Verwirrung, alle erwarten die Value-Semantik.
Vorteile:
Nachteile: