Geschiedenis van de vraag:
Go is ontworpen als een taal met expliciete value semantic: bijna alles wordt bij het doorgeven op waarde gekopieerd, inclusief structuren (struct), maar niet pointers en slices (slice). Dit vereenvoudigde het redeneren en verhoogde de veiligheid, maar bracht een aantal "valkuilen" met zich mee.
Probleem:
Ontwikkelaars verwachten vaak dat veranderingen in een struct die naar een functie wordt doorgegeven, ook "buiten" zichtbaar zijn. Maar het volledige inhoud wordt gekopieerd (inclusief geneste velden — op waarde!). Voor slices en maps geldt ander gedrag, waarbij de "container" wordt gekopieerd, maar niet de "inhoud".
Oplossing:
Geef grote structuren door via een pointer als veranderingen worden verwacht. Voor slice wordt alleen de descriptor (length, capacity, pointer) gekopieerd, en niet de inhoud — veranderingen aan de originele slice (via index) zullen extern zichtbaar zijn. Voor struct - alles wordt gekopieerd:
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 }
Belangrijke kenmerken:
Als je de struct in de functie verandert, verandert de originele?
Nee, als de struct op waarde wordt doorgegeven - de veranderingen zijn lokaal.
type User struct {Name string} func f(u User) {u.Name = "Ann"}
Als je een element van de slice in de functie verandert, verandert de originele?
Ja. Slices zijn een "weergave" op een gedeeld array. Door een element te veranderen, verander je ook de oorspronkelijke gegevens.
func f(s []int) {s[0] = 99}
Wat gebeurt er als je een slice retourneert die binnen de functie is gemaakt?
De "kop" van de slice wordt gekopieerd, maar de underlying array blijft toegankelijk. Als je de referentie niet buiten houdt, kunnen de gegevens door de GC worden verzameld.
In de functie werd de verwerking van de User-struct op waarde gedaan - veranderingen kwamen niet terug, bugs waren moeilijk op te sporen.
Voordelen:
Nadelen:
Grote structuren worden duidelijk via pointer doorgegeven, en voor slices wordt altijd het gedrag gedocumenteerd of gecontroleerd. Er is geen verwarring, iedereen verwacht value-semantic.
Voordelen:
Nadelen: