Ответ
Ключевое различие в том, как nil-значения map и slice ведут себя при операциях записи.
Хотя zero value для обоих типов — это nil, их поведение кардинально отличается.
Zero Value для map
- Значение:
nil. - Поведение: Попытка записи в
nil-map вызовет панику (panic: assignment to a nil map). Чтение, вызовlenилиrangeдляnil-map безопасны и не вызовут панику (вернут zero value для типа значения и 0 соответственно). - Инициализация: Перед использованием
mapдля записи её необходимо явно инициализировать с помощьюmake()или литерала.
var m map[string]int // m is nil
fmt.Println(m["key"]) // Безопасно, вернет 0
fmt.Println(len(m)) // Безопасно, вернет 0
m["key"] = 1 // !!! panic: assignment to a nil map
// Правильная инициализация
m = make(map[string]int)
m["key"] = 1 // OK
Zero Value для slice
- Значение:
nil. - Поведение:
nil-слайс можно безопасно использовать со встроенной функциейappend. При первом вызовеappendдляnil-слайса Go автоматически выделит память под новый нижележащий массив. Однако обращение к элементу по индексу вызовет панику. - Инициализация: Явная инициализация перед
appendне требуется.
var s []int // s is nil, len(s) == 0, cap(s) == 0
// Безопасно: Go выделит память и добавит элемент
s = append(s, 42)
fmt.Println(s) // Выведет [42]
fmt.Println(len(s)) // Выведет 1
// А вот так делать нельзя
var s2 []int // s2 is nil
s2[0] = 100 // !!! panic: runtime error: index out of range
Сравнительная таблица
| Операция | var m map[T]T (nil map) |
var s []T (nil slice) |
|---|---|---|
Чтение (v := m[k]) |
✅ Безопасно | ❌ Паника (по индексу) |
len() |
✅ Безопасно (возвращает 0) | ✅ Безопасно (возвращает 0) |
Запись (m[k] = v) |
❌ Паника | ❌ Паника (по индексу) |
append() |
(неприменимо) | ✅ Безопасно |
Ответ 18+ 🔞
А, слушай, тут один нюанс, который вгоняет в ступор, как будто тебе на голову упал кирпич, но ты не понял, откуда. Речь про nil-овые map и slice.
Вот смотри, оба они по дефолту — nil, ну, как и положено. Но ведут себя, как два разных мудака на одной вечеринке. Один молча в углу сидит, а второй внезапно начинает орать и бить посуду.
Нулевая map — это пидарас шерстяной
- Что такое:
nil. - Как себя ведёт: Попробуй в неё что-то записать — получишь пиздец, прямую панику в лицо:
panic: assignment to a nil map. А вот читать из неё, мерять длину или итерироваться — пожалуйста, на здоровье, вернёт нули и молча сдохнет. - Что делать: Перед тем как совать в неё данные, её надо родить через
make()или литерал. Иначе — в рот меня чих-пых.
var m map[string]int // m — это нихуя, nil
fmt.Println(m["key"]) // Ну ок, прочитал 0, похуй
fmt.Println(len(m)) // 0, всё чинно
m["key"] = 1 // !!! ЁБАНА В РОТ! ПАНИКА! assignment to a nil map
// Делай по-человечески
m = make(map[string]int)
m["key"] = 1 // Теперь всё охуенно
Нулевой slice — хитрая жопа
- Что такое: Тоже
nil. - Как себя ведёт: А вот это уже интереснее. Этого уёбка можно безопасно кормить функцией
append. Первый раз, когда ты сунешь в него элемент, Go сам, по-тихому, выделит память под массив. Но! Если ты попробуешь ткнуть в него пальцем по индексу — опять пиздец, паника. - Что делать: С
appendможно даже не париться, он сам всё сделает. Главное — не лезь по индексу в пустой слайс.
var s []int // s — нихуя, nil, len=0, cap=0
// А вот так можно, он сам внутри всё создаст
s = append(s, 42)
fmt.Println(s) // [42], красота
fmt.Println(len(s)) // 1, всё пучком
// А вот так — НИЗЯ!
var s2 []int // s2 — нихуя
s2[0] = 100 // !!! ОПЯТЬ ПАНИКА! index out of range
Короче, таблица, чтобы не ебал мозг
| Действие | var m map[T]T (nil мапа) |
var s []T (nil слайс) |
|---|---|---|
Прочитать (v := m[k]) |
✅ Можно, вернёт 0 | ❌ Паника (если по индексу) |
len() |
✅ Можно, вернёт 0 | ✅ Можно, вернёт 0 |
Записать (m[k] = v) |
❌ ПИЗДЕЦ, ПАНИКА | ❌ Паника (если по индексу) |
append() |
(не пришьёшь к жопе) | ✅ МОЖНО, ОН САМ ВСЁ СДЕЛАЕТ |
Вот и вся разница. Один — истеричка, с которым надо церемониться. Второй — пофигист, который работает через append. Запомни и не путай, а то runtime тебе ебальник набьёт.