Geschiedenis van de vraag:
Slices zijn een van de belangrijkste dynamische structuren in Go, ontstaan als alternatief voor arrays met een vaste lengte om het gebruiksgemak en de efficiëntie van geheugen te verhogen. Ze bieden flexibele interactie met subsetten van arrays, maar hebben verschillende nuances die belangrijk zijn voor productieve en veilige code.
Probleem:
Veel ontwikkelaars begrijpen niet precies hoe slices zijn opgebouwd: een slice is niet de array zelf, maar een structuur met een pointer naar de array, de lengte en capaciteit (capacity). Dit kan leiden tot geheugenlekken, bugs bij het werken met kopieën en onverwachte effecten wanneer de oorspronkelijke array wordt gewijzigd.
Oplossing:
Een slice is een type:
type slice struct { ptr unsafe.Pointer len int cap int }
Bij het uitbreiden van een slice met append() kan er een herschikking van de backing array plaatsvinden, en alle eerdere verwijzingen naar de oude array blijven geldig, maar verwijzen naar oude gegevens. Onwetendheid over deze eigenschap leidt tot fouten en geheugenlekken.
Voorbeeld van correcte geheugenallocatie en kopiëren:
src := []int{1,2,3,4,5} dst := make([]int, len(src)) copy(dst, src)
Een slice, gemaakt met [:], deelt de underlying array, en hun aanpassing beïnvloedt elkaar, tenzij copy is uitgevoerd.
Belangrijke kenmerken:
Wat gebeurt er bij het vergroten van een slice via append die de cap overschrijdt, als andere slices verwijzingen naar dezelfde array hebben?
append creëert bij overschrijding van cap een underlying array met een nieuwe geheugentoewijzing, en alleen deze slice verwijst naar de nieuwe array, terwijl de anderen naar de oude verwijzen. Dit is een veel voorkomende oorzaak van gegevensdiscrepanties.
Waarom is het belangrijk om geen langlevende slices van kleine omvang, verkregen uit een grote array, op te slaan?
Zelfs als de slice zeer klein is, houdt de pointer een verwijzing naar de hele backing array vast, wat kan leiden tot het vasthouden van de grote array in het geheugen en geheugenlekken.
Wat gebeurt er als je een array buiten zijn grenzen slice?
Er ontstaat een panic: runtime error: slice bounds out of range.
Een functie leest een groot bestand in een array van bytes en retourneert een slice van de eerste 100 elementen. Deze slice blijft lange tijd opgeslagen, maar al het geheugen voor de grote array blijft bij de GC.
Voordelen:
Nadelen:
Direct na het verkrijgen van de slice wordt het nodige stuk gekopieerd naar een nieuwe slice met make en copy. De oude array wordt onmiddellijk vergeten, en de GC vrijmaakt het geheugen.
Voordelen:
Nadelen: