Что выведет этот код и почему на Go 1.27 поведение стало особенно интересным?
package main
import (
"fmt"
"reflect"
)
func makeFn(x int) func() int {
return func() int {
return x
}
}
func main() {
a := makeFn(10)
b := makeFn(20)
pa := reflect.ValueOf(a).Pointer()
pb := reflect.ValueOf(b).Pointer()
fmt.Println(a(), b())
fmt.Println(pa == pb)
}
Интуитивно хочется сказать:
a и b замыкают разные значения, значит это две разные функции и адреса должны отличаться.
Но в Go 1.27 компилятор стал агрессивнее объединять одинаковый машинный код function literals.
У a и b может быть:
один и тот же code pointer
но разное closure data
поэтому a() возвращает 10, а b() - 20
То есть функция в Go на уровне runtime - это не просто адрес машинного кода.
У замыкания фактически есть ещё окружение с захваченными данными.
Именно поэтому сравнивать функции по reflect.Value.Pointer() как способ определить, «одна ли это функция», нельзя.
Go 1.27 специально предупреждает: разные closure с разными захваченными данными теперь могут чаще иметь одинаковые code pointers из-за оптимизаций компилятора.