Перейти к содержанию

Слайсы (часть 2)

Теперь — про подводные камни. Слайс это не сам массив, а «окно» в массив. Несколько слайсов могут смотреть на одни и те же данные, и одно изменение случайно ломает другой слайс. Это самый частый источник багов у новичков.

Что должен понять

  • Что слайс — это тройка (указатель, len, cap).
  • Что такое shared backing array и как два слайса делят память.
  • Как сделать независимую копию через copy.
  • Что делает выражение s[low:high:max] (ограничение cap).
  • Как append может создать новый массив, а может писать в чужой.

Shared backing array

arr := []int{1, 2, 3, 4, 5}
a := arr[1:4]       // [2 3 4]
b := arr[2:5]       // [3 4 5]

a[1] = 99           // меняем arr[2]
fmt.Println(arr)    // [1 2 99 4 5]
fmt.Println(b)      // [99 4 5]   <-- b тоже изменился

a и b смотрят в один и тот же массив. Изменение через одно «окно» видно через другое.

Slicing с тремя индексами s[low:high:max]

max ограничивает cap, чтобы будущий append не залез в чужую память:

arr := []int{1, 2, 3, 4, 5}
safe := arr[1:3:3]            // len=2, cap=2
safe = append(safe, 99)       // создаст новый массив
fmt.Println(arr)              // [1 2 3 4 5] — не пострадал

Без третьего индекса append мог бы записать поверх arr[3].

copy — независимая копия

src := []int{1, 2, 3}
dst := make([]int, len(src))
n := copy(dst, src)           // n = 3
dst[0] = 99
fmt.Println(src, dst)         // [1 2 3] [99 2 3]

copy копирует min(len(dst), len(src)) элементов.

append: когда new array, когда нет

  • Если len < capappend пишет в существующий массив, ёмкость хватает.
  • Если len == cap — Go аллоцирует новый массив (обычно ×2) и копирует.
s := make([]int, 0, 4)
s = append(s, 1, 2, 3, 4)  // тот же массив
s = append(s, 5)           // новый массив, cap вырос

Из-за этого функция, принимающая слайс, может или поменять оригинал, или работать с копией — в зависимости от ёмкости. Всегда присваивай результат append обратно.

Частые ошибки

  • Сделали b := a[2:4], поменяли b[0] и удивляются, что a изменился.
  • В цикле копируют через b = a — это тот же слайс, а не копия.
  • Передают слайс в функцию, ждут что не изменится — а функция делает s[0] = 0 и оригинал ломается.
  • Используют arr[1:3] в долгоживущей переменной, держа в памяти весь большой массив. Если нужен только кусок — копируй.

Критерии приёмки модуля

  • Программа демонстрирует shared backing array на двух слайсах.
  • Программа делает независимую копию через copy и доказывает, что изменение копии не трогает оригинал.
  • Программа использует s[low:high:max] хотя бы один раз.
  • Решение не выходит за границу слайса.

Дальше: Мапы.