🔴 Сложный · 3 очк. defer, panic, recover
Что вернёт func f() (r int) { defer func() { r++ }(); return 0 }?
A 0
B 1
C panic
D Ошибка компиляции
Объяснение вопроса

Это классический вопрос на понимание того, как defer взаимодействует с именованными возвращаемыми значениями. Ответ: функция вернет 1.

Что происходит пошагово

Оператор return в Go - это не атомарная операция. Он состоит из трех шагов:

  1. Вычисление возвращаемого значения и присвоение его именованной переменной
  2. Выполнение всех deferred функций
  3. Фактический возврат из функции
func f() (r int) {
    defer func() { r++ }()
    return 0
}

// Шаг 1: r = 0      (return 0 присваивает r = 0)
// Шаг 2: r++        (defer увеличивает r до 1)
// Шаг 3: return r   (возвращается 1)

Ключевой момент: замыкание

Deferred функция - это замыкание, которое захватывает переменную r по ссылке. Когда замыкание выполняет r++, оно модифицирует ту же переменную, которую функция собирается вернуть.

Сравнение: с именованным и без

// С именованным возвращаемым значением:
func withNamed() (r int) {
    defer func() { r = 100 }()
    return 0
}
// Вернет 100 - defer перезаписал r

// Без именованного возвращаемого значения:
func withoutNamed() int {
    r := 0
    defer func() { r = 100 }()
    return r
}
// Вернет 0 - defer изменил локальную переменную,
// но возвращаемое значение уже зафиксировано

Практическое применение

Этот паттерн часто используется для обработки ошибок:

func doWork() (err error) {
    f, err := os.Open("file.txt")
    if err != nil {
        return err
    }
    defer func() {
        closeErr := f.Close()
        if err == nil {
            err = closeErr // перезаписываем err через defer
        }
    }()
    // ... работа с файлом ...
    return nil
}

Здесь defer может установить ошибку закрытия файла как возвращаемое значение, если основная работа прошла успешно (err == nil).

🧠Квиз 🏆Лидеры 🎯Собесед. 📖Вопросы 📚База зн.