Skip to content

Goの関数アドレスは型パラメータ毎に別の型として扱われる

Goのreflect.Value.Pointerは基本的に関数のアドレスを返すが、ジェネリックな関数を型パラメータでインスタンス化(instantiate)したとき、そのアドレスは型パラメータごとに異なる。型引数が同じ型であっても異なるアドレスになる。

ただし、Goのreflectで同じ型かどうかを検査するで書いたように、ジェネリックな関数の場合でもreflect.Typeは同じ型として扱われる。型引数が異なっていれば当然だけどreflect.Typeも異なる。

package main
import (
"fmt"
"reflect"
)
func M[T any](v T) {
fmt.Println(v)
}
func helloT[T any]() {
v := reflect.ValueOf(M[T])
fmt.Println("helloT:", v.Pointer())
}
func hello[T any]() {
v1 := reflect.ValueOf(M[int])
v2 := reflect.ValueOf(M[T])
v3 := reflect.ValueOf(M[byte])
fmt.Println("hello1:", v1.Pointer())
fmt.Println("hello2:", v2.Pointer())
helloT[T]()
fmt.Println("same:", v1.Type() == v2.Type())
fmt.Println("diff:", v3.Type() == v2.Type())
}
func main() {
fmt.Println("main:", reflect.ValueOf(M[int]).Pointer())
hello[int]()
// Output:
// main: 4720544
// hello1: 4720544
// hello2: 4719840
// helloT: 4720000
// same: true
// diff: false
}

以下の場合は同じ型として扱われる。

  • 異なる関数で F[T] (Tが同じ)
  • 異なるパッケージで F[T] (Tが同じ)
  • 異なるモジュールで F[T] (Tが同じ)