プログラミング
Go 1.27 のジェネリックメソッド
Generic Methods in Go 1.27 (dominik.info)
要約
Go 1.18 で導入されたジェネリクスは、関数や構造体に型パラメータをもたらしましたが、メソッドには適用されませんでした。Go 1.27 のリリースにより、この制限が解消され、メソッドはレシーバー構造体に型パラメータを追加することなく、独自の型パラメータを定義できるようになりました。この変更は、ジェネリクスがコンパイル時に解決されるのに対し、Go のインターフェースシステムが実行時に動作するという実装上の課題から、長らく実現が遅れていました。
全文翻訳
2026年8月20日
2022年にGo 1.18がジェネリクスを導入した際、型パラメータは関数と構造体に導入されましたが、メソッドには適用されませんでした。Go 1.27のリリースにより、この長年の制限が解消されました。メソッドは、レシーバー構造体に型パラメータを追加することなく、独自の型パラメータを定義できるようになりました。
この変更が導入された理由
ジェネリックな値を持つグラフノードを作成したい場合、次のように実装するかもしれません。
type Node[T any] struct {
value T
}
ノードの型Tを別の型Uのノードに変換するMapメソッドを追加すると想像してください。Go 1.27より前は、UをNode構造体自体に追加することを余儀なくされていました。
type Node[T any, U any] struct {
value T
}
func (n *Node[T, U]) Map() Node[T, U] {
// ...
}
Uを構造体自体に追加するのは悪い設計です。なぜなら、UはMapに固有の型パラメータだからです。他のメソッドがUを使用しない場合でも、レシーバー宣言にUを含める必要がありました。
唯一の回避策は、Mapをメソッドではなくパッケージレベルの関数として実装することでした。関数は独自の型パラメータを定義できたからです。しかし、メソッドはできなかったため、ぎこちなく非イディオマティックなAPI設計につながりました。
Go 1.27以降では、UをMapメソッド専用に定義できます。
func (n *Node[T]) Map[U any]() Node[U] {
// ...
}
なぜこれほど時間がかかったのか?
答えはGoでのジェネリクスの実装方法にあります。コンパイラは主にモナド化(monomorphization)を使用してジェネリクスを処理します。これは、ジェネリックな構造体や関数のコピーを、それらが使用されるすべての特定の型に対して作成することを意味します。なぜなら、ある時点で、ジェネリクスの抽象的な概念を直接的なマシンコードに変換する必要があるからです。
しかし、Goのインターフェースシステムは実行時に機能します。インターフェースパラメータに渡される値の具体的な型は、プログラムの実行中に解決されます。この動的なディスパッチは、コンパイル時に解決されるジェネリクスと衝突します。
Mapメソッドをインターフェースで宣言したい場合に何が起こるかを考えてみてください。
type Mapper interface {
Map[T any, U any](element T) U
}
これを機能させるには、実行時が、オンザフライで特定の型のマシンコードを生成するためのジャストインタイムコンパイラを必要とするか、または事前にすべての可能な型のコピーを作成する必要があり、結果としてバイナリが大幅に肥大化します。
最終的に、Goチームはジェネリックメソッドをインターフェースから分離することを決定しました。Go 1.27は、具体的な型に対するジェネリックメソッドを許可しますが、インターフェースに対するものは許可しません。この区別が、上記の例がコンパイルされない理由であり、それに関する議論に時間がかかった理由です。
さらに読む
Go 1.27 Release Notes (go.dev)
Proposal: Generic Methods for Go (GitHub)
The Performance of Generics in Go (dominik.info)
A Gentle Introduction to Generics in Go
Go 1.18でのジェネリクスのリリースは、言語における大きな変更です。ジェネリクスはどのように機能しますか?パフォーマンスにどのように影響しますか?いつ意味がありますか?初心者向けのまとめ。
Go • 2022年10月1日
The Performance of Generics in Go
Goにおけるジェネリクスの実装とパフォーマンス特性の解説。
Go • 2022年4月30日