Коллекции: массивы, срезы и отображения

Массивы и срезы: создание, индексирование, len, cap, append и range

Содержание курса

append с обязательным присваиванием и for range по срезу

append — единственный стандартный способ добавить элемент в срез. Он принимает срез и один или несколько новых значений, а возвращает обновлённый срез:

s := []int{1, 2, 3}
s = append(s, 4)
fmt.Println(s) // [1 2 3 4]

Обычная форма в этом уроке — s = append(s, v). Главное правило: используйте возвращённый срез. Его длина увеличена на число добавленных элементов, а базовый массив мог сохраниться или смениться — это зависит от текущей ёмкости и остаётся деталью реализации.

Результат append можно также присвоить другой переменной, вернуть из функции или сразу передать следующему вызову. Что недопустимо — полностью игнорировать возвращённое значение:

append(s, 4) // ошибка компиляции: append(s, 4) evaluated but not used

Программа не соберётся. Go требует, чтобы возвращённый срез был использован.

append отлично работает с nil-срезом — вы видели его в предыдущей секции:

var s []int
s = append(s, 10, 20)
fmt.Println(s) // [10 20]

Для перебора среза используйте цикл for range:

s := []string{"go", "is", "fun"}
for i, v := range s {
    fmt.Println(i, v)
}
// 0 go
// 1 is
// 2 fun

i — индекс, v — копия элемента. Это важно. Если написать:

for _, v := range s {
    v = "changed" // не меняет s
}

— срез останется нетронутым. v — локальная переменная итерации, изменение которой не отражается на оригинале. Чтобы изменить элемент, нужно присваивание по индексу:

for i := range s {
    s[i] = "changed"
}
fmt.Println(s) // [changed changed changed]

Форма for i := range s даёт только индекс — используйте её, когда значение элемента в теле цикла не нужно. Если нужно только значение без индекса, отбросьте индекс через _:

for _, v := range s {
    fmt.Println(v)
}

Самопроверка: append не гарантирует отдельный массив

Создайте срез и его подсрез, измените элемент подсреза и посмотрите на исходный. Затем добавьте элемент через append. Если capacity хватает, добавление может использовать прежний базовый массив, а при нехватке памяти выделяется новый. Поэтому вывод «после append срезы всегда независимы» неверен.

Для копирования создайте целевой срез подходящей длины и вызовите copy. Проверьте именно length, а не только capacity: copy записывает не больше минимальной длины источника и назначения. Указатель на общий массив объясняет поведение лучше, чем запоминание отдельных примеров. Разберите это до задач, где функция изменяет полученный slice.

Продолжите разбор: Разделяемый базовый массив, copy и подсрезы.

Начать заново?

Помощник начнёт новый диалог по этой задаче. Текущая переписка останется в истории до конца срока хранения.

О переписке

Можно приложить до трёх фото PNG, JPEG или WebP по 5 МБ.

Переписка и фото хранятся 90 дней после последнего принятого сообщения. Преподаватель получит доступ к диалогу, когда вы попросите его помочь.

Проверка решения остаётся отдельным действием.