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

Массивы и срезы: создание, индексирование, 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)
}