タラバガニー設計局stalins.clubNOTE/notes/method-expression

メソッド式とメソッド値

ジェネリクスメソッドでもメソッド式・メソッド値は変わらず使えるが、レシーバ側がジェネリック型の場合は先に instantiate しておく必要がある。

type List[E any] struct{ ... }
func (*List[E]) format[F any](E, F) string { ... }

List[string].format  // => [F any](string, F) string   OK
List.format          // NG (List が未インスタンス化)

List.format を書いても [E any, F any](E, F) string のような、レシーバとメソッド両方の型パラメータを持つ関数にはならない。提案 #77273 本文の言葉を借りれば「メソッドがジェネリックなら、結果の関数もジェネリックになる」だけで、レシーバ側の型パラメータはメソッド式を作る前に確定していなければならない。

これは「レシーバは単なる第一引数」というモデルの反例のひとつでもある (メソッドはレシーバを持つ関数)。レシーバが本当にただの第一引数なら、List.formatEF の両方を型パラメータに持つ関数になってよさそうだが、実際にはそうならない。レシーバの型引数とメソッド自身の型引数は、性質の異なる2つの経路として扱われている。

メソッド値が取れない場合があることは、実務上の互換性問題にも直結する。既存の非ジェネリックなメソッドに型パラメータを後付けすると、それまで書けていた

_ = g.Do

のようなメソッド値の取得がコンパイルエラーになる。これは言語機能としては正しい挙動だが、「型パラメータを足すだけの一見無害なリファクタ」が実は破壊的変更になる、という話につながる。詳細と実例 (x/sync/singleflightGroup.Do) は 既存メソッドへの型パラメータ後付けは破壊的変更 に譲る。

出典

  • Go Release Party 1.27 の発表資料リポジトリ memo.md §1
  • #77273

▸ ノート一覧に戻る