В чём разница между zero value для map и slice в Go?

Ответ

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