Как компилятор Go обрабатывает вложенные функции?

Как компилятор обрабатывает вложенную функцию при написании в Go? Превращается ли она в другую функцию и помещается вне кода, или она воссоздается каждый раз при вызове родительской функции?

Например:

func FuncA() int {
    a := 0
    funcB := func(_a int) int {
        return _a
    }
    return funcB(a)
}

Эта функция скомпилирована следующим образом?

func FuncA() int {
    a := 0
    return _funcB(a)
}
func _funcB(_a int) int {
    return _a
}

Или он скомпилирован точно так, как написано, что означает, что новая память выделяется для определения funcB каждый раз, когда FuncA вызывается?

Какой из нескольких компиляторов Go? Для какой платформы? gc, ориентированный на S360, может делать это иначе, чем tinygo, нацеленный на WASM.

Volker 28.11.2022 07:02

@Volker: Сколько компиляторов существует для Golang? Хотя был только один (и версия GCC тоже)

Arnold Zahrneinder 28.11.2022 07:13

gcc использует тот же код для среды выполнения, что и gc, но есть несколько других, среди которых наиболее заметным является tinygo, другие gopherjs и gollvm (список не является исчерпывающим). (Обратите внимание, что я не верю, что они отличаются тем, как компилируются вложенные функции.)

Volker 28.11.2022 08:44

@Volker, семантика замыканий не меняется от компилятора к компилятору. Вот почему мой ответ говорит: «скомпилированный код эквивалентен...»

Burak Serdar 28.11.2022 16:19
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
API ввода вопросов - это полезный инструмент для интеграции моделей машинного обучения, таких как ChatGPT, в приложения, требующие обработки...
1
4
84
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вложенные функции компилируются один раз.

Поскольку FuncB не закрывает переменные в окружающей области видимости, FuncA не выделяет память кучи.

Если FuncB закрыл какие-либо переменные в окружающей области, то эти переменные будут выделены в куче. Сама функция компилируется один раз.

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

 func FuncA() int {
    a := 0
    funcB := func() int {
        return a
    }
    return funcB()
}

Скомпилированный код эквивалентен:

type closureB struct {
   a int
}

func FuncA() int {
  c:=new(closureB)
  c.a=0
  return funcB(c)
}

func funcB(c *closureB) int {
  return c.a
}

Точные детали зависят от среды выполнения и реализации компилятора.

Другие вопросы по теме