Нужно ли передавать map в Go по указателю и почему
Что проверяют
Понимаете ли вы, что в Go всё передаётся по значению, и знаете ли, что именно лежит в переменной типа map. Вопрос на понимание модели памяти, а не на заучивание слов «ссылочный тип».
Как отвечать
По указателю не нужно почти никогда. Значение карты это маленький заголовок, по сути указатель на хеш-таблицу внутри рантайма. Копируется он за одно и то же время независимо от того, десять там ключей или миллион, и копия смотрит на ту же таблицу, поэтому записи внутри функции видны снаружи.
func add(m map[string]int) { m["a"] = 1 } // видно вызывающему
func reset(m *map[string]int) { *m = make(map[string]int) } // тут указатель нуженУказатель оправдан в одном случае: функция должна подменить саму карту у вызывающего, то есть присвоить новую или инициализировать ту, что равна nil. Аргумент про производительность не работает: копируется одно машинное слово, размер карты на это не влияет. Указатель скорее вредит, появляется лишнее разыменование и второй способ получить nil.
Где спотыкаются
Говорят «карта передаётся по ссылке». В Go передачи по ссылке нет вообще, копируется значение, просто это значение указатель. На соседнем вопросе про слайс такой ответ и разваливается: append внутри функции вызывающий не увидит, потому что заголовок слайса скопирован.
Считают, что раз таблица общая, писать в неё можно из нескольких горутин. Конкурентная запись это не гонка с непредсказуемым значением, а аварийное завершение рантайма с сообщением про concurrent map writes. Нужен sync.RWMutex или sync.Map под свой профиль нагрузки.
Забывают про нулевое значение. Поле структуры, которое никто не инициализировал, равно nil: чтение из такой карты спокойно вернёт ноль, а первая же запись уронит программу. Карту создают через make в конструкторе.