Что возвращают функции, принимающие структуру по значению и по указателю в Go
Что проверяют
Понимаете ли вы, что в Go всё передаётся по значению, и знаете ли, что именно копируется при копировании структуры. Заодно проверяют, осознанно ли вы выбираете вид получателя у методов.
Как отвечать
Функция с параметром-структурой получает копию. Изменения полей внутри наружу не видны, вернуть их можно только вернув структуру. Функция с параметром *T тоже получает копию, но копию указателя, а он ведёт к тому же объекту, поэтому запись в поля видна вызывающему.
func rename(p Person) { p.Name = "b" } // оригинал не меняется
func renamePtr(p *Person) { p.Name = "b" } // меняетсяВажная тонкость: копия поверхностная. Слайс, мапа, канал или указатель внутри структуры копируются как заголовки, а данные за ними общие. Поэтому передача по значению не даёт изоляции: p.Tags[0] = x изменит оригинал.
Про возвращаемые значения: возврат структуры это тоже копия, возврат *T отдаёт адрес, и локальная переменная при этом живёт дальше, escape-анализ сам переносит её в кучу. У методов набор для T и *T разный: методы с указательным получателем входят только в набор *T, поэтому в интерфейс кладут &v.
Где спотыкаются
Считают, что получатель по значению защищает от мутации. Он защищает только сами поля, а слайс или мапа внутри остаются общими, и метод «только для чтения» тихо портит данные вызывающего.
Второе: копируют структуру, внутри которой лежит sync.Mutex или sync.WaitGroup. Копия получает свою блокировку, защита перестаёт работать, и это одна из немногих ошибок, которую ловит go vet.
Третье: повторяют правило «указатель всегда быстрее». Маленькую структуру дешевле скопировать, а указатель часто выгоняет объект в кучу и нагружает сборщик мусора. Выбор делается по размеру и по необходимости мутации, а спор решается бенчмарком.