Ответ
Ключевое различие в том, как 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() | (неприменимо) | ✅ Безопасно |