タラバガニー設計局stalins.clubNOTE/notes/rand-n-only-stdlib-generic-method

標準ライブラリ唯一のジェネリクスメソッド rand.N

math/rand/v2N は Go 1.22 の時点でパッケージレベル関数として存在していた。だが設計当時はメソッドとしてジェネリクスを持てなかったため、*Rand のメソッドにはできず、関数だけが生えるという非対称な状態が続いていた。

// [0,n) の乱数を n と同じ整数型で返す。Go 1.22 から関数だけあった
func N[Int intType](n Int) Int

// Go 1.27 でメソッドが追加された (#77853)
func (r *Rand) N[Int intType](n Int) Int

メソッド版の追加提案 #77853 は本体 ジェネリクスメソッド (Go 1.27) (#77273) の acceptance を待って出され、2026-05-21 に accepted になった。「言語機能が無かったから関数のままだった非対称を、機能が入った直後に解消する」という目的がきれいな提案である。

api/go1.27.txt を全部見ても、自前の型パラメータを持つメソッドはこの Rand.N 1件だけである (2026-08-15 時点)。標準ライブラリはジェネリクスメソッドという道具を得た直後で、まだほとんど使っていない。

副作用: cmd/api への波及

generic method は method set に入らない扱いのため、API チェッカ (cmd/api) がそのままだと Rand.N を拾わなかった。CL「cmd/api: emit generic methods kept out of method sets」(#79737) で専用対応が入っている。言語機能が1つ増えると、周辺ツールにも個別の手当てが要ることを示す小さな実例である。

go vet 側への波及

std 唯一の generic method である Rand.N が起点になって go vet 側に2件の issue が動いた。

  • #80360 (release-blocker, closed 2026-07-13) — vendoring された x/tools/internal/stdlib が古く、Go 1.27 の新 API を pre-1.27 モジュールで使っても vet が警告しなかった。rc1/rc2 に向けて index を更新して修正された。
  • #80363 (closed 2026-07-14) — 診断メッセージが rand.N requires go1.27 or later と出るが、正しくは rand.(*Rand).N であるべきだった。prattmic が発見し、dmitshur は「generic methods の regression ではなく、stdversion がメソッド一般をこう表示していた問題」とコメントしている。

提案中で止まっているメソッド版

reflect.Value.TypeAssert[T any] (#78008) と Value.Unpack[T any] (#78007) は、2026-08-15 時点でどちらも open のまま、2026-03 から議論が止まっている。ただしこれは generic method 待ちで止まっていたのではなく、意味論 (nil interface に対して何を返すべきか、など) で揉んでいるためである。

なお、パッケージレベル関数の reflect.TypeAssert[T any](Value) (T, bool) はすでに Go 1.25 で追加済み (#62121)。メソッド版だけが宙に浮いている状態であり、両者を混ぜて話すと誤りになる。

出典

▸ ノート一覧に戻る