Получить доступ

Почему изменение одного среза неожиданно меняет другой?

JuniorСрезы, мапы и строки
Ещё спрашивают так:
  • Какие ловушки есть у append в Go?
Коротко

Срезы, полученные друг из друга, делят базовый массив, пока append не перевыделил его. Если у исходного среза есть свободная ёмкость, append к подсрезу перезапишет элементы исходного. Поведение зависит от cap — поэтому баг проявляется не всегда.

  • Защита: копия (slices.Clone, copy) или полное выражение среза a[i:j:j]
  • Возвращая внутренний срез из структуры, отдают доступ к её данным
  • Две горутины, делающие append к одному срезу, — гонка

А ещё Тот же эффект при передаче среза в функцию, которая делает append

Так подсказку видит пользователь sotto на живом собеседовании — за пару секунд, пока вы думаете вслух.

Попробуйте сами

Срезы Go: len, cap, append и общий массив

Подробно

Механика. b := a[:2] — новый дескриптор с длиной 2, но ёмкость наследуется (10). append(b, 99) видит свободное место и пишет в третью ячейку общего массива — ту же, что a[2].

Где встречается:

  • функция принимает срез, делает append и использует результат, а вызывающий продолжает работать со старым — данные перемешиваются;
  • несколько срезов строятся из общего буфера в цикле;
  • метод возвращает внутренний срез структуры, и снаружи его дополняют.

Правила: если срез нужно хранить или модифицировать независимо — скопировать; при нарезке общего буфера — ограничивать ёмкость третьим индексом.

Пример

a := make([]int, 3, 10)      // [0 0 0], cap 10
b := a[:2]                   // [0 0], тот же массив
b = append(b, 99)            // места хватает — пишет в a[2]
fmt.Println(a)               // [0 0 99]

c := a[:2:2]                 // cap ограничен 2
c = append(c, 7)             // новый массив, a не меняется

Что хотят услышать

  • Общий массив и роль ёмкости.
  • Способы защиты.

Связанные вопросы

Закрытая бета

Подсказки на собеседовании — в реальном времени

sotto слышит вопрос интервьюера и показывает короткий ответ и план, как в блоке «Коротко». Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем