Устройство defer в golang

Есть следующий кусок кода:

   func f1() int {
        var x int
        defer func() { 
            x+=90
        }()
        x = 1
        return x 
    }

Функция f1 всегда будет возвращать 1.

Есть другая функция:

func f2() (x int) {
    defer func() { 
        x+=90
    }()
    x = 1
    return
}

Функция f2 всегда будет возвращать 91.

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


Ответы (1 шт):

Автор решения: Pak Uula

В ваших примерах отложенная функция использует переменную x из внешнего окружения. Когда компилятор ищет кандидата на добавление в замыкание, он просматривает код вверх по тексту, до первого символа с именем x, видимого в точке определения отложенной функции.

В первом примере

   func f1() int {
        var x int
        defer func() { 
            x+=90
        }()

первый встреченный символ x связан с внутренней переменной. Отложенная функция эту переменную обновит, но на результат это уже не повлияет, так как результат записан в стек, и (внимание) адрес области стека с возвращаемым значением не равен области, отведённой для внутренней переменной x.

Во втором примере

func f2() (x int) {
    defer func() { 
        x+=90
    }()

компилятор свяжет символ x внутри отложенной функции с символом x, обозначающим возвращаемое значение функции. Поэтому результат вычисления выражения x+=90 будет записан как раз в ту область стека, где хранится возвращаемое значение.

→ Ссылка