16 вопросов
Слайсы - основная структура данных для работы с коллекциями в Go. Важно понимать их внутреннее устройство (указатель + длина + ёмкость) и отличие от массивов.
var s []int; fmt.Println(s == nil)? 🟢 Лёгкий
▶
Неинициализированный слайс имеет zero value nil. nil-слайс можно использовать с len() (вернёт 0), cap() (вернёт 0) и append() без ошибок. Но make([]int, 0) создаёт пустой не-nil слайс.
Подробнее →cap(make([]int, 3, 10))? 🟢 Лёгкий
▶
make([]int, length, capacity) - второй аргумент задаёт длину, третий - ёмкость. cap() возвращает ёмкость (10), len() - длину (3). Ёмкость определяет, сколько элементов можно добавить без переаллокации.
Подробнее →Массив [3]int - фиксированный размер, часть типа. [3]int и [4]int - разные типы. Слайс []int - динамический, это ссылка на массив (указатель + длина + ёмкость). Массивы передаются по значению, слайсы - по ссылке.
Подробнее →Функция copy(dst, src) копирует элементы из src в dst, возвращая количество скопированных элементов. b = a - это не копирование, а создание второй ссылки на тот же массив.
Подробнее →len(make([]int, 5, 10))? 🟢 Лёгкий
▶
make([]int, 5, 10) создаёт слайс длиной 5 и ёмкостью 10. len() возвращает длину (количество доступных элементов), а не ёмкость. Элементы 0–4 инициализированы нулями.
Подробнее →a := [3]int{1,2,3}; b := a; b[0] = 99; fmt.Println(a[0])? 🟡 Средний
▶
Массивы в Go - value types. Присваивание b := a создаёт полную копию. Изменение b[0] не затрагивает a. Это ключевое отличие от слайсов, которые разделяют базовый массив.
Подробнее →append(s, 1, 2, 3)? 🟡 Средний
▶
append не изменяет оригинальный слайс - он возвращает новый. Если ёмкости хватает, новый слайс ссылается на тот же массив. Если нет - Go аллоцирует новый массив побольше. Всегда используйте: s = append(s, ...).
Подробнее →В Go нет встроенной функции удаления из слайса. Идиоматический способ - склеить части до и после удаляемого элемента через append. delete() работает только с map.
Подробнее →==? 🟡 Средний
▶
Слайсы нельзя сравнивать между собой через == - это ошибка компиляции. Единственное допустимое сравнение - с nil. Для сравнения содержимого используйте slices.Equal() (Go 1.21+) или цикл.
Подробнее →clear(s) для слайса s := []int{1, 2, 3} (Go 1.21+)? 🟡 Средний
▶
Встроенная функция clear() для слайсов обнуляет все элементы zero value, но не меняет длину и ёмкость. После clear(s): s = [0, 0, 0], len(s) = 3. Для map clear удаляет все ключи.
Подробнее →s := []int{1,2,3}; s2 := s[1:]; s2[0] = 99? 🔴 Сложный
▶
Подслайс s[1:] разделяет базовый массив с s. s2[0] и s[1] указывают на один и тот же элемент в памяти. Изменение через s2 видно через s. Чтобы получить независимую копию, используйте copy.
Подробнее →a := make([]int, 2, 4); b := append(a, 1); _ = append(a, 2); fmt.Println(b[2])? 🔴 Сложный
▶
Оба append работают с одним базовым массивом (cap=4 хватает). Первый append записывает 1 в позицию [2]. Второй append тоже пишет в позицию [2], перезаписывая 1 на 2. b[2] теперь 2. Классическая ловушка разделяемой ёмкости.
Подробнее →s := []int{1,2,3,4,5}; s2 := s[1:3:3]; s2 = append(s2, 99); fmt.Println(s[3])? 🔴 Сложный
▶
Трёхиндексный слайс s[1:3:3] ограничивает ёмкость: len=2, cap=2. При append ёмкости не хватает - Go выделяет новый массив. s[3] остаётся 4. Без третьего индекса s[1:3] имел бы cap=4, и append перезаписал бы s[3].
Подробнее →big := make([]byte, 1<<20); small := big[:10]; big = nil? 🔴 Сложный
▶
small ссылается на тот же базовый массив размером 1 МБ. Пока small жив, GC не может его освободить. Решение: copy(newSlice, big[:10]). Частая проблема при чтении больших файлов, когда сохраняют маленький кусочек.
Подробнее →s := []int{1, 2, 3}; a := [3]int(s) (Go 1.20+)? 🔴 Сложный
▶
Go 1.17 добавил конвертацию слайса в указатель на массив: (*[3]int)(s). Go 1.20 - прямую конвертацию: [3]int(s). Результат - копия данных, не ссылка. Если len(s) < 3 - panic. Полезно для функций, ожидающих массив фиксированного размера.
Подробнее →С Go 1.18: плавный рост - удвоение до 256 элементов, затем формула newcap += (newcap + 3*256) / 4. Это даёт плавный переход от 2x к ~1.25x. Точный cap может отличаться из-за выравнивания памяти аллокатором. Раньше: удвоение до 1024, затем +25%.
Подробнее →