Ответ
Оператор return в Go завершает выполнение текущей функции и опционально возвращает значения вызывающей стороне. Его поведение имеет несколько ключевых особенностей:
1. Возврат значений в соответствии с сигнатурой функции
Если функция объявлена с возвращаемыми типами, return должен вернуть значения именно этих типов. Если функция не возвращает значений, return используется для досрочного выхода из неё.
// Функция с возвращаемым значением
func sum(a, b int) int {
return a + b
}
// Функция без возвращаемых значений
func printIfPositive(n int) {
if n <= 0 {
return // Досрочный выход
}
fmt.Println(n)
}
2. Именованные возвращаемые значения и "голый" return
В Go можно именовать возвращаемые значения прямо в сигнатуре функции. Эти переменные доступны внутри функции как обычные локальные переменные и автоматически возвращаются при использовании return без аргументов (так называемый "голый" или "naked" return).
- Преимущество: Улучшает читаемость, особенно в функциях с несколькими возвращаемыми значениями одного типа.
- Недостаток: Чрезмерное использование "голого"
returnв длинных функциях может ухудшить понимание кода, так как неясно, какие значения возвращаются в данный момент.
func divide(a, b float64) (result float64, err error) {
if b == 0 {
err = errors.New("division by zero")
return // Возвращает (0.0, err)
}
result = a / b
return // Возвращает (result, nil)
}
3. Взаимодействие с defer
Это одна из самых важных особенностей. Отложенные (defer) функции выполняются после того, как return вычислил свои аргументы, но до того, как функция фактически вернёт управление.
Если функция использует именованные возвращаемые значения, defer может их прочитать и изменить.
func getNumber() (n int) { // n инициализируется нулём
defer func() {
n++ // Этот код выполнится перед возвратом и изменит n
}()
n = 5
return n // 1. n присваивается значение 5. 2. defer увеличивает n до 6. 3. Функция возвращает 6.
}
// getNumber() вернёт 6
4. return в функции main
Вызов return в функции main завершает её выполнение, что приводит к немедленному завершению всей программы. Это аналогично выходу из программы после выполнения последней строки в main.
Ответ 18+ 🔞
Давай разберём этот ваш return, а то я вижу, у некоторых с ним, как с манда с ушами, полная путаница. Запомни раз и навсегда, это не просто "выход", это целый ёперный театр с отложенными вызовами и подвохами.
1. Возвращает то, что обещал, и точка.
Объявил, что функция int возвращает — возвращай int. Не объявил — можешь просто return вставить и свалить по-тихому. Проще пареной репы.
// Обещал int — вот тебе int, получи и распишись.
func sum(a, b int) int {
return a + b
}
// Ничего не обещал — можно просто смыться, если что.
func printIfPositive(n int) {
if n <= 0 {
return // Всё, я пас, дальше не играю.
}
fmt.Println(n)
}
2. Именованные возвраты и "голый" возврат — палка о двух концах.
Можно прямо в заголовке функции переменные для возврата объявить. Удобно, особенно когда возвращаешь кучу всего одного типа — сразу видно, что есть что. А потом можно написать просто return, и он эти переменные сам вернёт. Это называется "голый" return.
- Плюс: Читаемость на высоте, не надо гадать,
(int, int)— это что первое, что второе. - Минус: Если функция длинная, как роман Толстого, а ты где-то в середине пишешь
return, то нихуя не понятно, какие значения в этих именованных переменных на тот момент. Может, они ещё нулевые, а может, ты их десять раз перезаписал. Подозрение ебать чувствую к такому коду.
func divide(a, b float64) (result float64, err error) {
if b == 0 {
err = errors.New("деление на ноль, гений") // Записали ошибку в именованную переменную.
return // Голый возврат! Вернёт (0.0, нашу ошибку). Удобно.
}
result = a / b // Записали результат.
return // Вернёт (результат, nil). Тоже удобно.
}
3. А теперь главный фокус — return и defer. Вот где пиздец начинается.
Запомни как "Отче наш": отложенные функции (defer) выполняются ПОСЛЕ того, как return посчитал, что ему возвращать, но ДО того, как функция реально отдала управление.
А если у тебя именованные возвращаемые значения, то defer может их не только посмотреть, но и, сука, ПЕРЕПИСАТЬ. Вот это поворот, да?
func getNumber() (n int) { // n тут уже есть, равен 0.
defer func() {
n++ // Внимание! Этот кусок кода выстрелит прямо перед уходом и накинет n единичку.
}()
n = 5
return n // Шаг 1: return видит, что n = 5. Шаг 2: СРАБАТЫВАЕТ defer и делает n = 6. Шаг 3: Функция наконец-то сваливает, возвращая 6.
}
// Вызов getNumber() даст тебе 6, Карл! Не 5!
Вот так вот. Кажется, что вернёшь пятёрку, а defer тебе в последний момент подсунул шестёрку. Хитрая жопа.
4. return в main — это приговор.
Вызвал return в главной функции — всё, конец программы, приехали. Как будто последняя строчка кода выполнилась. Всё заканчивается тут же.