Как компилятор обрабатывает вложенную функцию при написании в 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
вызывается?
@Volker: Сколько компиляторов существует для Golang? Хотя был только один (и версия GCC тоже)
gcc использует тот же код для среды выполнения, что и gc, но есть несколько других, среди которых наиболее заметным является tinygo, другие gopherjs и gollvm (список не является исчерпывающим). (Обратите внимание, что я не верю, что они отличаются тем, как компилируются вложенные функции.)
@Volker, семантика замыканий не меняется от компилятора к компилятору. Вот почему мой ответ говорит: «скомпилированный код эквивалентен...»
Вложенные функции компилируются один раз.
Поскольку 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
}
Точные детали зависят от среды выполнения и реализации компилятора.
Какой из нескольких компиляторов Go? Для какой платформы? gc, ориентированный на S360, может делать это иначе, чем tinygo, нацеленный на WASM.