Возврат нескольких значений
Перечислите типы результатов в скобках. Возвращайте значения через запятую и принимайте так же.
Встроенные min и max появились в Go 1.21. Вызывающий код обязан принять все результаты: x := minMax(nums) не компилируется с ошибкой assignment mismatch: 1 variable but minMax returns 2 values.
Соглашение (value, error)
Чаще всего два значения возвращают, чтобы сообщить об ошибке. По соглашению ошибка идёт последней, и если она не nil, остальные результаты считаются бессмысленными.
Вывод:
port: 8080
error: port "http": strconv.Atoi: parsing "http": invalid syntax
error: port out of range
При ошибке возвращайте нулевое значение для всех остальных результатов (0, "", nil). Полный шаблон, включая оборачивание и проверку, описан на странице обработка ошибок.
Идиома comma-ok
Несколько встроенных операций возвращают необязательное второе значение bool, которое говорит, настоящее ли первое значение. Переменную по соглашению называют ok.
Эти три формы (поиск в мапе, утверждение типа, получение из канала) особые: они возвращают одно или два значения в зависимости от того, скольким переменным вы присваиваете. Ваши собственные функции так не умеют. Функция, объявленная с двумя результатами, всегда возвращает два.
Пустой идентификатор
_ принимает значение и выбрасывает его. Используйте его для ненужных результатов:
_, err := fmt.Sscan(input, &n)
key, _ := parseLine(line)
Игнорирование ошибки через _ компилируется, поэтому делайте так, только если точно знаете, что вызов не может завершиться неудачей или неудача не важна. Например, strings.Builder.WriteString всегда возвращает nil-ошибку, а закрытие файла после записи нет.
Именованные результаты
У параметров результата могут быть имена. Они объявляются в начале функции, инициализируются нулевыми значениями, а return без значений возвращает то, что в них лежит.
Имена попадают в вывод go doc, что помогает, когда у двух результатов один тип: (quotient, remainder int) говорит больше, чем (int, int).
Голый return в длинной функции трудно читать: читателю приходится листать назад, чтобы понять, что лежит в результатах. Обычный совет: называйте результаты, когда имена что-то документируют, и всё равно пишите return quotient, remainder явно, если функция длиннее нескольких строк.
Именованные результаты и defer
Отложенная функция выполняется после того, как инструкция return записала результаты, и до того, как их получит вызывающий код. С именованными результатами отложенная функция может читать и менять их. Так добавляют контекст к любой ошибке, которую возвращает функция, или превращают панику в ошибку.
Программа печатает load : empty name, а затем <nil>. return errors.New(...) сначала присваивает значение err, а затем отложенная функция его оборачивает. Подробнее на странице о defer.
Затенение именованного результата
Именованные результаты живут во внешней области видимости функции. := во вложенном блоке создаёт новую переменную с тем же именем, и голый return вернёт внешнюю.
func find() (n int, err error) {
if true {
n, err := compute() // new n and err, shadowing the results
_ = n
_ = err
}
return // returns 0, nil
}
Худший случай компилятор ловит: голый return внутри блока, где результат затенён, даёт ошибку result parameter err not in scope at return. Вариант выше, где return стоит вне блока, он не ловит. Используйте = вместо :=, когда имеете в виду переменные результата.
Частые ошибки
- Использование значения, когда err не nil. Сначала проверьте
err. Функция вправе вернуть мусор вместе с ошибкой. - Возврат типизированного nil-указателя в качестве ошибки.
var e *MyErr; return eвозвращает не-nilerror. При успехе возвращайте литералnil. - Слишком много результатов. Три и больше результатов разного смысла неудобны в использовании. Верните структуру.
Часто задаваемые вопросы
Как вернуть несколько значений из функции в Go?
Перечислите типы результатов в скобках и верните значения через запятую: func minMax(xs []int) (int, int) { ...; return lo, hi }. Вызывающий код присваивает их все сразу: lo, hi := minMax(nums).
Как проигнорировать одно из возвращаемых значений в Go?
Присвойте его пустому идентификатору _: _, err := strconv.Atoi(s) или n, _ := strconv.Atoi(s). Совсем пропустить значение нельзя: число переменных слева должно совпадать с числом результатов.
Что такое именованные возвращаемые значения в Go?
Параметры результата, у которых есть имена, например func split(n int) (half, rest int). Они начинаются с нулевых значений, им можно присваивать в теле, а голый return возвращает их текущие значения. Ещё они позволяют отложенной функции изменить то, что получит вызывающий код.
Стоит ли использовать голый return в Go?
Только в коротких функциях. Голый return в длинной функции скрывает, что именно возвращается, и облегчает баги с затенением. Руководства по стилю Go советуют называть результаты ради документации, а в функциях длиннее нескольких строк возвращать значения явно.