De structuren map en slice in Go hebben belangrijke kenmerken met betrekking tot kopiëren en geheugensemantiek, die vaak leiden tot onverwacht gedrag bij onervaren ontwikkelaars.
Hoewel Go wordt beschouwd als een strikte taal met statische typificatie en het ontbreken van pointers per default, hebben map en slice een speciale interne model: beide types zijn referentietypes. Dit legt beperkingen op en creëert veel nuances bij het kopiëren en doorgeven van deze objecten.
Het kopiëren van een map en slice leidt niet tot een diepe kopie van de inhoud, maar vormt een nieuwe referentie naar hetzelfde object, wat leidt tot onverwachte bijeffecten bij het wijzigen van gegevens, onjuiste waardeterugkeer uit functies en mutaties. Bovendien kan het retourneren van een map of slice als resultaat van een functie extra allocaties of lekken veroorzaken.
b := a[:]). Voor een volledige kopie van de elementen moet de ingebouwde functie copy() worden gebruikt.Voorbeeld van correcte kopie:
// Kopiëren van een slice a := []int{1, 2, 3} b := make([]int, len(a)) copy(b, a) // b is nu onafhankelijk van a // Kopiëren van een map src := map[string]int{"x": 1} dst := make(map[string]int) for k, v := range src { dst[k] = v }
Belangrijke kenmerken:
slice en map zijn referentietypes, worden gekopieerd op basis van hun descriptor, niet op hun inhoudWat gebeurt er als je eenvoudig een map/slice aan de andere toewijst en vervolgens een van hen wijzigt?
Zowel de map als de slice wijzen naar dezelfde gegevens in het geheugen: wijziging zal effect hebben op beide objecten.
Waarom zegt men vaak "dit is efficiënt in termen van geheugen" bij het retourneren van een slice of map uit een functie?
Omdat de descriptor wordt gekopieerd in plaats van de hele inhoud; de gegevens in de heap blijven leven zolang er referenties naar zijn.
Kun je met de functie copy() "diepe" kopieën van een map maken?
Nee, copy() werkt alleen met slices en arrays, voor de map is altijd een loop nodig.
Een ontwikkelaar kopieert een slice of map door toewijzing en wijzigt de kopie om zich te beschermen tegen bijeffecten:
Voordelen:
Nadelen:
Voor het wijzigen van noodzakelijke gegevens wordt copy() gebruikt voor slice en een loop voor map:
Voordelen:
Nadelen: