Массивы и срезы: создание, индексирование, len, cap, append и range
Содержание курса
Срез []T: литерал, make([]T, len, cap), len, cap и nil-срез
Срез []T — динамическая последовательность. В отличие от массива, у него нет числа в скобках, и его длина не является частью типа: все []int — один и тот же тип, сколько бы элементов в них ни было.
Два способа создать срез — литерал и make.
Литерал:
s := []int{1, 2, 3}
fmt.Println(len(s), cap(s)) // 3 3
Здесь len и cap совпадают, потому что срез создан ровно под три элемента.
make даёт больше контроля:
s := make([]int, 3, 5)
fmt.Println(len(s), cap(s)) // 3 5
Доступны только те индексы, что меньше len: s[0], s[1], s[2] — всё, эти три элементы равны нулю. Попытка обратиться к s[3] или s[4] вызовет панику, потому что они выходят за пределы длины. Правило простое: допустимый диапазон индексов — от 0 до len(s)−1, и никак иначе. append возвращает срез с увеличенной длиной, открывая тем самым новые индексы — но об этом в следующей секции.
Если третий аргумент опустить, cap равен len:
s := make([]int, 4)
fmt.Println(len(s), cap(s)) // 4 4
Инвариант всегда один: len(s) <= cap(s). Это гарантия языка, нарушить её через обычный код невозможно.
Отдельный случай — nil-срез. Это нулевое значение типа []T:
var s []int
fmt.Println(s == nil) // true
fmt.Println(len(s), cap(s)) // 0 0
nil-срез — не ошибка. Он валиден, его можно передавать в функции и применять к нему append. Просто в нём пока ноль элементов и ноль ёмкости.
