Функции
Функции в Go — множественные и именованные возвраты, вариативные параметры, функции как значения первого класса и рекурсия.
7 вопросов
JuniorТеорияОчень частоКак работают множественные и именованные возвраты в Go?
Как работают множественные и именованные возвраты в Go?
Функция в Go может вернуть сразу несколько значений, идиоматически пару (T, error) как return val, err. Результаты можно и поименовать: именованные результаты — это заранее объявленные переменные, которые стартуют с нулевого значения и видны во всём теле функции, что позволяет «голый» return, отправляющий их текущие значения. В присваивании вызывающий связывает каждый результат, а ненужные отбрасывает через _.
Типичные ошибки
- ✗Думать, что «голый»
returnигнорирует именованные результаты, а не шлёт их текущие значения - ✗Пропускать результат в присваивании:
v := f()дляfс двумя результатами не компилируется, поэтому каждому результату нужна переменная или_.
Уточняющие вопросы
- →Когда «голый»
returnвредит читаемости, хотя и легален? - →Как отложенное замыкание взаимодействует с именованным возвращаемым значением?
JuniorТеорияЧастоЧто выведет программа?
Что выведет программа?
11
Открыть задачу →Типичные ошибки
- ✗Ждать
14:*связывает сильнее+, поэтому1 + x*2— это1 + (x*2), а не(1 + x)*2;f(2)равно5, аf(5)равно11. - ✗Ждать
5или5 11: результат внутреннего вызова5снова передаётся вf, аfmt.Printlnпечатает только значение своего аргумента —f(5).
Уточняющие вопросы
- →Что напечатает
fmt.Println(f(2), f(f(2)))? - →Как изменить
f, чтобы она вычисляла(1 + x) * 2?
JuniorТеорияЧастоЧто выведет программа?
Что выведет программа?
5 6
Открыть задачу →Типичные ошибки
- ✗Ждать
6 6:r := op(2, 3)сразу вызывает функцию и сохраняет число 5, а не саму функцию. - ✗Ждать
5 5или ошибку компиляции: функция — значение, и переменной типаfunc(int, int) intможно присвоить другой литерал того же типа.
Уточняющие вопросы
- →Как анонимная функция становится замыканием над окружающими переменными?
- →Каково нулевое значение переменной функционального типа и что будет при её вызове?
JuniorТеорияЧастоЧто выведет программа?
Что выведет программа?
2 1
Открыть задачу →Типичные ошибки
- ✗Ждать
2 2:n— копияx, поэтомуn++меняет только копию;incвозвращает2, аxостаётся1. - ✗Ждать
1 1или ошибку компиляции: параметр — обычная переменная функции, поэтомуn++разрешён и меняетn, которуюincзатем возвращает.
Уточняющие вопросы
- →Как изменить
main, чтобы самаxстала равна2? - →Что напечатает программа, если параметр
incназватьxвместоn?
JuniorТеорияЧастоЧто такое вариативный параметр в Go и как он передаётся?
Что такое вариативный параметр в Go и как он передаётся?
Запись ...T у последнего параметра делает функцию вариативной: она собирает любое число хвостовых аргументов в срез []T, поэтому внутри тела параметр — обычный срез, по которому можно итерироваться. Вызывают её отдельными аргументами вроде f(a, b, c) или разворачивают существующий срез через f(s...). Стандартные функции вроде append и fmt.Println устроены именно так.
Типичные ошибки
- ✗Забывать, что вариативный параметр должен быть последним в сигнатуре
- ✗Передавать срез напрямую вместо разворота через форму
s... - ✗Считать собранные аргументы массивом, а не срезом
[]T
Уточняющие вопросы
- →Что даёт внутри тела передача нуля аргументов вариативному параметру?
- →Почему вариативный вызов иногда размещает базовый массив в куче?
JuniorТеорияИногдаЧто выведет программа?
Что выведет программа?
321123
Открыть задачу →Типичные ошибки
- ✗Ждать
321: строка после рекурсивного вызова тоже выполняется, когда вызов вернётся, поэтому каждыйcountпечатаетnдважды. - ✗Ждать
123321или321321: самый глубокий вызов завершается первым, поэтому вторые печати идут в обратном порядке: 1, 2, 3.
Уточняющие вопросы
- →Какую ошибку или панику вы получите, когда рекурсия в Go исчерпает стек?
- →Чем растущий по требованию стек горутины отличается от фиксированного стека в C?
MiddleТеорияИногдаКак отложенная функция может изменить именованное возвращаемое значение?
Как отложенная функция может изменить именованное возвращаемое значение?
Именованные результаты — это настоящие переменные, остающиеся в области до фактического возврата из функции, даже после того как return их задал. Отложенное замыкание — само значение-функция первого класса — выполняется в этом окне, поэтому может прочитать и переприсвоить их: defer func(){ err = wrap(err) }() перезаписывает то, что получит вызывающий. С безымянными возвратами это невозможно, ведь не остаётся переменной, к которой отложенный вызов мог бы обратиться.
Типичные ошибки
- ✗Думать, что defer получает копию результата, а не живую переменную
- ✗Ждать того же приёма с безымянными возвратами, где переменной нет
- ✗Считать, что defer выполняется до того, как
returnзадал результат, а не после
Уточняющие вопросы
- →В каком порядке применяются несколько отложенных правок одного именованного результата?
- →Почему этот шаблон част для оборачивания или аннотирования ошибки перед выходом из функции?