panic: assignment to entry in nil map
panic: assignment to entry in nil mapПрограмма записала значение в map, которую не создали, и аварийно остановилась — в Go это называется паникой. Переменная, объявленная как var m map[string]int, равна nil: читать из неё можно (всегда получите нулевое значение), а записывать — нет. Решение — создать map до первой записи:
m := make(map[string]int)
m["a"] = 1или литералом:
m := map[string]int{}Где nil-map прячется
Поле структуры. Создание структуры не создаёт map в её полях — поле остаётся nil:
type Inventory struct {
Items map[string]int
}
var inv Inventory
inv.Items["яблоки"] = 5 // паника: Items == nilОбычное решение — функция-конструктор, которая создаёт всё нужное:
package main
import "fmt"
type Inventory struct {
Items map[string]int
}
func NewInventory() *Inventory {
return &Inventory{Items: make(map[string]int)}
}
func main() {
inv := NewInventory()
inv.Items["яблоки"] += 5
inv.Items["яблоки"] += 2
fmt.Println(inv.Items["яблоки"], len(inv.Items))
}7 1Другой вариант — создавать map лениво, то есть только когда она понадобится: в методе, перед первой записью: if inv.Items == nil { inv.Items = make(…) }.
Map внутри map. Внешняя map создана, а внутренние — нет: для нового ключа outer["Минск"] возвращает nil.
package main
import "fmt"
func main() {
visits := make(map[string]map[string]int)
add := func(city, page string) {
if visits[city] == nil {
visits[city] = make(map[string]int)
}
visits[city][page]++
}
add("Минск", "/")
add("Минск", "/")
add("Брест", "/news")
fmt.Println(visits["Минск"]["/"], visits["Брест"]["/news"], len(visits))
}2 1 2Без проверки if visits[city] == nil первая же запись visits[city][page]++ вызвала бы панику.
Map из функции или после json.Unmarshal. Функция может вернуть nil вместо map, а json.Unmarshal оставляет map в поле структуры равной nil, если такого поля в JSON нет. Проверьте результат перед записью или создайте map сами.
Что можно делать с nil-map
- читать:
m["x"]вернёт нулевое значение,v, ok := m["x"]—okбудетfalse; - узнать длину:
len(m)— 0; - перебирать:
for k, v := range mпросто не выполнится ни разу; - удалять:
delete(m, "x")ничего не сделает.
Нельзя только записывать. Поэтому ошибка часто всплывает не сразу, а там, где программа впервые что-то добавляет.
Как прочитать сообщение паники
Под первой строкой Go печатает стек — где именно случилась паника:
goroutine 1 [running]:
main.main()
/home/user/hello/main.go:7 +0x…
exit status 2Ищите первую строку с файлом своей программы — здесь это main.go:7, седьмая строка. Путь, номер строки и адреса у вас будут свои. Строка exit status 2 — это go run сообщает, что программа завершилась с ошибкой.