В Go можно явно объявлять имена возвращаемых значений в сигнатуре функции. Такие значения автоматически инициализируются zero value для своего типа. Это удобно при работе с большим количеством возвращаемых переменных, позволяет неявно "возвращать" значения через оператор return (без аргументов).
Пример:
func foo() (x int, err error) { if someCheck() { x = 1 return // вернётся (1, nil) } return // вернётся (0, nil), если x и err не были присвоены явно }
Тонкости:
nil для error). Это может замаскировать ошибки в логике.Что будет возвращено функцией с именованными результатами, если внутри не будет ни одного присваивания возвращаемым переменным и вызван просто return?
Ответ: Будут возвращены их zero values. Например, для int — 0, для указателя — nil.
Пример:
func test() (res *MyType, code int) { return // то же самое, что "return nil, 0" }
История
В финансовом сервисе забыли присвоить переменной err (error) значение внутри функции с именованными возвратами. Из-за этого, при сбое, функция возвращала nil, а ошибка терялась. В результате сломалась обработка транзакций, и часть операций прошла незамеченной.
История
При рефакторинге функции добавили новый именованный возвращаемый результат, но несовместимость с предыдущим возвращаемым типом не была замечена — тесты пропустили проблему из-за возврата нулевого значения, что привело к silent bag в хранилище.
История
В одной из вспомогательных функций логировали ошибки через именованный результат, но иногда забывали обрабатывать их не только при возврате, но и в логировании, что приводило к сложным для воспроизведения багам ("error lost").