programowanieProgramista Go

Jak działa copy() w Go przy kopiowaniu slice'ów? Jakie są cechy, ograniczenia i nieoczekiwane efekty związane z wzrostem długości i pojemności slice'a? Co się dzieje, gdy slice'y nachodzą na siebie i próbujemy je skopiować z nakładką?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź

Funkcja copy(dst, src []T) int kopiuje elementy z src do dst.

  • Zwraca liczbę skopiowanych elementów: min(len(dst), len(src)).
  • Kopiowanie odbywa się indeksowo: elementy src[i] są kopiowane do dst[i].
  • Kopiowane są zawartości (wartości), a nie wskaźniki do obiektów.

Szczegóły i ograniczenia:

  • Jeśli slice'y nachodzą na siebie (na przykład jeden jest podtablicą drugiego), kopiowanie odbywa się tak, jakby najpierw wzięto fragment pierwotnych wartości, a następnie skopiowano (brak gwarancji poprawności przy nakładaniu).
  • Jeśli dst ma mniejszą długość niż src, skopiowane zostanie tylko tyle danych, ile pozwala długość dst.
  • Jeśli dst ma większą pojemność niż długość, czy copy rozszerza slice? — Nie, tylko len(dst) jest brane pod uwagę. Aby rozszerzyć — użyj wcześniej append.

Przykład:

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

Nakładanie:

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

Pytanie z haczykiem

Czy copy() może być użyte do zwiększenia długości slice'a? Co się stanie, jeśli przekażesz do copy slice-o-destynację o większej pojemności, ale mniejszej długości niż potrzebne?

Odpowiedź:

  • copy() nie zmienia długości docelowego slice'a — tylko kopiuje do len(dst)
  • Jeśli dst ma pojemność większą niż długość, najpierw rozszerz go przez dst = dst[:newLen], a następnie użyj copy()

Przykład, często nieoczywisty:

a := []int{1,2,3} b := make([]int, 0, 5) copy(b, a) // b pozostanie pusty, ponieważ len(b)==0 b = b[:len(a)] copy(b, a) // teraz b: [1,2,3]

Przykłady rzeczywistych błędów z powodu nieznania szczegółów tematu


Historia

W projekcie kopiowano dane z jednego slice'a do drugiego, zakładając, że copy automatycznie rozszerzy długość dst do wymaganej. Tak się nie stało, elementy nie zostały skopiowane, w wyniku czego w odpowiedzi API pojawiały się dane zerowe. Błąd znaleziono dopiero po porównaniu długości slice'ów — problemem okazało się to, że dst miało dużą pojemność, ale długość wynosiła 0.


Historia

Część mikroserwisu pracowała z nachodzącymi slice'ami, błędnie zakładając, że copy zawsze zadziała poprawnie. W rezultacie kopiowanie do przodu niszczyło oryginalne dane, pojawiały się "niewidoczne" błędy w pracy z buforami. Rozwiązano to poprzez użycie tymczasowego bufora (copy(tmp, src), potem copy(dst, tmp)).


Historia

Inżynier optymalizował tablicę, używając copy do porządkowania danych między slice'ami. Oczekiwał, że copy skoryguje długość dst. Okazało się, że tak się nie stało, i zaczęły pojawiać się paniki i wyjścia poza ramy danych — zapomniano poprawnie zmienić długość slice'a przed kopiowaniem.