In Go werden standardmäßig alle Funktionsargumente durch Wert übergeben: Der Wert der Variable wird kopiert. Aber einige Typen (zum Beispiel Slices, Maps, Channels) sind "Wrapper" über internen Strukturen (Zeigern). Die Übergabe eines Slices durch Wert kopiert nur den Deskriptor des Slices, nicht die Daten; beide Variablen verweisen auf dasselbe Array. Im Fall von Strukturen wird die gesamte Struktur kopiert.
Wenn man das Kopieren vermeiden und mit der Originalstruktur arbeiten möchte, verwendet man die Übergabe durch Zeiger (*Struct).
type User struct { Name string Age int } func updateUser(u User) { u.Age = 30 // ändert nur die Kopie } func updateUserPtr(u *User) { u.Age = 30 // ändert das Original } func main() { u := User{"Ivan", 25} updateUser(u) fmt.Println(u.Age) // 25 updateUserPtr(&u) fmt.Println(u.Age) // 30 }
Sind Änderungen an einem Slice, das an eine Funktion übergeben wurde, immer außerhalb der Funktion sichtbar?
Nein!
slice[i] = ...), ist diese Änderung außerhalb sichtbar.slice = append(slice, ...)), und das Ergebnis nicht aus der Funktion zurückgegeben wird — die neuen Elemente werden in einer lokalen Kopie sein, und man wird sie verlieren.func addElem(s []int) { s = append(s, 100) } func main() { arr := []int{1,2,3} addElem(arr) fmt.Println(arr) // [1 2 3] — 100 wurde nicht hinzugefügt }
Geschichte
In einem der Projekte wurden Datentypen mit einem großen struct-Feld (200+ Bytes) durch Wert über Kanäle zwischen Goroutinen übergeben, was enorme Kopierkosten und Leistungsabfälle verursachte. Nach dem Wechsel zur Übergabe durch Zeiger verringerte sich die Latenz um das Zehnfache.
Geschichte
In einem Auditing-Logging-Service übergab ein Entwickler eine Map zwischen Funktionen, ohne eine explizite Klonierung (copy) vorzunehmen. Änderungen, die von einer Funktion vorgenommen wurden, veränderten unerwartet Daten in einem anderen Teil des Programms, was zu Verwirrung im Log führte.
Geschichte
In einer Funktion zum dynamischen Vergrößern eines Slices innerhalb der Funktion wurde vergessen, das neue Slice zurückzugeben. Infolgedessen wurden die Änderungen nicht im aufrufenden Code reflektiert, was zu einem Verlust von Transaktionen führte. Es wurde beschlossen, das neue Slice aus der Funktion zurückzugeben.