ПрограммированиеSenior Go Developer

Как работают именованные возвращаемые значения в Go? Какие преимущества и опасности связаны с их использованием, и в чем заключаются особенности zero values в этом контексте?

Проходите собеседования с ИИ помощником Hintsage

Ответ

В Go можно явно объявлять имена возвращаемых значений в сигнатуре функции. Такие значения автоматически инициализируются zero value для своего типа. Это удобно при работе с большим количеством возвращаемых переменных, позволяет неявно "возвращать" значения через оператор return (без аргументов).

Пример:

func foo() (x int, err error) { if someCheck() { x = 1 return // вернётся (1, nil) } return // вернётся (0, nil), если x и err не были присвоены явно }

Тонкости:

  • Если забыть явно присвоить ошибку переменной, вернётся её zero value (обычно это nil для error). Это может замаскировать ошибки в логике.
  • Zero values для именованных результатов используются для инициализации и возврата по умолчанию.
  • Используйте именованные результаты с осторожностью: они повышают читаемость только там, где возврат из функции имеет однозначный смысл.

Вопрос с подвохом

Что будет возвращено функцией с именованными результатами, если внутри не будет ни одного присваивания возвращаемым переменным и вызван просто return?

Ответ: Будут возвращены их zero values. Например, для int — 0, для указателя — nil. Пример:

func test() (res *MyType, code int) { return // то же самое, что "return nil, 0" }

Примеры реальных ошибок


История

В финансовом сервисе забыли присвоить переменной err (error) значение внутри функции с именованными возвратами. Из-за этого, при сбое, функция возвращала nil, а ошибка терялась. В результате сломалась обработка транзакций, и часть операций прошла незамеченной.


История

При рефакторинге функции добавили новый именованный возвращаемый результат, но несовместимость с предыдущим возвращаемым типом не была замечена — тесты пропустили проблему из-за возврата нулевого значения, что привело к silent bag в хранилище.


История

В одной из вспомогательных функций логировали ошибки через именованный результат, но иногда забывали обрабатывать их не только при возврате, но и в логировании, что приводило к сложным для воспроизведения багам ("error lost").