Функции
Функция в Go объявляется через func, и на первый взгляд тут нечего разбирать: имя, скобки с параметрами, тип возврата, тело. Но именно функция — главная единица кода, и в ней живёт несколько идиом, без которых нельзя читать настоящий Go: функция возвращает сразу несколько значений, и пара value, err — это каркас всей обработки ошибок; параметр-многоточие ...int принимает любое число аргументов; сама функция — это значение, которое можно положить в переменную и передать дальше.
Под простым func прячется модель, которую и проверяют на собеседовании: множественный возврат — не кортеж, а несколько отдельных значений; именованные результаты предобъявлены и обнулены; вариативный параметр внутри — обычный слайс; функция первого класса передаётся как аргумент; а рекурсия растит стек горутины, потому что Go не гарантирует хвостовую оптимизацию. Эта тема разбирает функции по слоям — от возвратов до рекурсии.
Карта темы
- Множественные и именованные возвраты —
func f() (int, error)возвращает несколько значений; идиомаreturn value, err; именованные результаты(n int, err error)предобъявлены и обнулены, а голыйreturnотдаёт их — но злоупотреблять им не стоит. - Вариативные функции —
func f(xs ...int): внутриxs— обычный[]int; вызвать можно набором аргументов или «раскрыть» существующий слайс черезf(s...); вариативный параметр всегда последний. - Функции как значения — функции первого класса: их кладут в переменные, передают аргументами и возвращают из функций; тип функции
func(int) int; анонимные функции и немедленный вызовfunc(){…}(). - Рекурсия — функция, вызывающая саму себя; обязательный базовый случай; Go не гарантирует хвостовую оптимизацию, поэтому глубокая рекурсия растит стек горутины — для горячих глубоких циклов предпочтительнее итерация.
Частые ошибки и ловушки
| Ошибка | Последствие |
|---|---|
| Считать множественный возврат кортежем, который можно присвоить одной переменной | Это N отдельных значений: v, err := f() — на каждое нужна своя переменная (или _) |
Игнорировать второе возвращаемое значение err | Ошибка молча теряется — корень большинства багов в Go-коде |
| Думать, что именованный результат надо инициализировать вручную | Он предобъявлен и уже обнулён (0, "", nil); голый return отдаст текущее значение |
Злоупотреблять голым return в длинной функции | Неочевидно, что именно вернулось — на ревью это считают анти-паттерном |
Передавать слайс в вариативную функцию без ... | f(s) трактует слайс как один аргумент — нужно f(s...) для раскрытия |
| Ставить вариативный параметр не последним | Ошибка компиляции — ...T обязан быть последним в списке параметров |
| Забыть базовый случай в рекурсии | Бесконечный самовызов растит стек горутины до stack overflow и паники |
| Рассчитывать на хвостовую оптимизацию, как в функциональных языках | Go её не гарантирует — глубокая рекурсия съедает стек; для горячих циклов берут итерацию |
Значение для собеседований
Функции — частый junior-блок: спрашивают не «как объявить func», а понимание идиом за ним. Кандидат, который писал код по примеру, но не разбирал модель, спотыкается именно здесь.
Что обычно проверяют:
- Как работает множественный возврат и почему пара
value, err— основа обработки ошибок. - Что такое именованные результаты, чем они удобны и почему голым
returnзлоупотреблять не стоит. - Что вариативный параметр
...Tвнутри — это слайс, и как «раскрыть» существующий слайс черезs.... - Что функции в Go — значения первого класса: их можно присвоить переменной, передать и вернуть.
- Почему глубокая рекурсия в Go опасна (нет гарантированной хвостовой оптимизации, растёт стек) и когда вместо неё берут итерацию.