Отложенный вызов defer: различия между передачей значений и указателей

test3 печатает ptr as pointer=2020, ptr as value=20 и a=10. Однако весь main из фрагмента не компилируется, если отсутствующая test1 нигде не определена.

Короткий ответ

Что ответить на собеседовании

test3 печатает ptr as pointer=2020, ptr as value=20 и a=10. Однако весь main из фрагмента не компилируется, если отсутствующая test1 нигде не определена.

Подробный разбор

Ответ с пояснениями

Условие

Необходимо понять, какие данные будет выводить программа, если использовать оператор defer для функций, которые принимают как обычные значения, так и указатели.

func main() {
    fmt.Println(test1())
    test3()
}

func test3() {
    var a int = 10
    var b = 20
    var ptr *int = &b

    defer printInt("a", a)
    defer printInt("ptr as value", *ptr)
    defer printIntPointer("ptr as pointer", ptr)

    a = 1010
    *ptr = 2020
}

func changeI(i *int) {
    *i = 10
}

func printInt(label string, v int) {
    fmt.Printf("%s=%d\n", label, v)
}

func printIntPointer(label string, p *int) {
    fmt.Printf("%s=%d\n", label, *p)
}

Ответ

test3 печатает ptr as pointer=2020, ptr as value=20 и a=10. Однако весь main из фрагмента не компилируется, если отсутствующая test1 нигде не определена.

Аргументы defer вычисляются сразу: значения a и *ptr сохраняются как 10 и 20. В третьем вызове сохраняется адрес b, а разыменование происходит уже при выполнении, после записи 2020. Вызовы идут в обратном порядке. Результат test1 нельзя определить по этому фрагменту; changeI здесь вообще не вызывается.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее