ProgrammatieGo ontwikkelaar

Hoe werkt copy() in Go bij het kopiëren van slices? Wat zijn de kenmerken, beperkingen en onverwachte effecten die verband houden met de groei van de lengte en capaciteit van een slice? Wat gebeurt er bij overlapping van slices en de poging om ze met elkaar te kopiëren?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord

De functie copy(dst, src []T) int kopieert elementen van src naar dst.

  • Het retourneert het aantal gekopieerde elementen: min(len(dst), len(src)).
  • De kopie gebeurt indexmatig: de elementen src[i] worden gekopieerd naar dst[i].
  • De inhoud (waarden) wordt gekopieerd, niet de pointers naar objecten.

Fijnere punten en beperkingen:

  • Als de slices overlappen (bijvoorbeeld, de ene is een subarray van de andere), gebeurt de kopie alsof eerst een snapshot van de oorspronkelijke waarden is genomen en vervolgens is gekopieerd (er zijn geen garanties voor correctheid bij overlapping).
  • Als dst een kortere lengte heeft dan src, wordt alleen zoveel data gekopieerd als de lengte van dst toelaat.
  • Verhoogt copy de slice? — Nee, alleen len(dst) wordt als doel beschouwd. Voor uitbreiding — gebruik eerst append.

Voorbeeld:

a := []int{1,2,3,4,5} b := make([]int, 3) copy(b, a) // b: [1 2 3]

Overlapping:

x := []int{1,2,3,4} copy(x[1:], x[:3]) // [1 1 2 3]

Een misleidende vraag

Kan copy() worden gebruikt om de lengte van een slice te vergroten? Wat gebeurt er als je een slice met een grotere capaciteit, maar een kleinere lengte dan nodig, aan copy geeft?

Antwoord:

  • copy() verandert de lengte van de doel slice niet — het kopieert alleen tot len(dst)
  • Als dst een capaciteit heeft die groter is dan de lengte, verhoog deze dan eerst via dst = dst[:newLen], en gebruik dan copy()

Voorbeeld, vaak niet voor de hand liggend:

a := []int{1,2,3} b := make([]int, 0, 5) copy(b, a) // b blijft leeg omdat len(b)==0 b = b[:len(a)] copy(b, a) // nu b: [1,2,3]

Voorbeelden van echte fouten door onwetendheid over de fijne punten van het onderwerp


Verhaal

In het project werden gegevens van de ene slice naar de andere gekopieerd, in de veronderstelling dat copy de lengte van dst automatisch zou uitbreiden tot wat nodig was. Dit gebeurde niet, de elementen werden niet gekopieerd, met als resultaat dat nul gegevens in de API-respons kwamen. De fout werd pas gevonden na het vergelijken van de lengtes van de slices — het probleem was dat dst een grote capaciteit had, maar de lengte was 0.


Verhaal

Een deel van de microservice werkte met overlappende slices, in de veronderstelling dat copy altijd correct zou werken. Als gevolg hiervan vernietigde de voorwaartse kopie de originele gegevens, en ontstonden er "onzichtbare" bugs bij het werken met buffers. Dit werd opgelost door een tijdelijke buffer te gebruiken (copy(tmp, src), en vervolgens copy(dst, tmp)).


Verhaal

Een ingenieur optimaliseerde een array door copy te gebruiken om gegevens tussen slices te ordenen. Hij verwachtte dat copy de lengte van dst zou corrigeren. Het bleek dat dit niet gebeurde, en er ontstonden paniek en overschrijdingen van significante gegevens — hij vergat de lengte van de slice correct te wijzigen voor het kopiëren.