must: Do
要約
概要
Go標準ライブラリに must.Do のような汎用的な「エラーが非nilならpanicする」ヘルパー関数を追加するproposal。元々は url.MustParse という具体的な要望から始まり、regexp.MustCompile や template.Must のような既存パターンを一般化する must パッケージの提案へと発展した。
ステータス変更
active → likely_decline
Go 1.27でジェネリックメソッド(#77273)が実現し testing.T.Must[T any] が技術的に可能になったことを受けて再度アクティブに審査されたが、最終的に「単一の極めて小さな関数のためだけに新パッケージを追加するのは適切でない」「testing.T.Must はテストの意図をぼかす」という合意に至り、likely declineとなった。代わりに元の具体的な要望である url.MustParse が別issue #79946として切り出されてアクティブキューに追加された。
技術的背景
現状の問題点
Goには regexp.MustCompile、template.Must、netip.MustParseAddr など、「エラーが発生したらpanicする」関数がパッケージ固有に散在している。しかし汎用的なものがないため、各コードベースで同じようなヘルパーが繰り返し書かれている。
// 各プロジェクトで独自に実装されているパターン
func must[T any](v T, err error) T {
if err != nil {
panic(err)
}
return v
}
// 使用例:グローバル変数の初期化
var target = must(url.Parse("https://example.com"))
Tailscaleは tailscale.com/util/must、Ridgeは github.com/ridge/must など、多くの著名なコードベースが独自実装を持っている。
提案された解決策
標準ライブラリに must パッケージを追加し、以下のような関数を提供する:
// must.Get: (T, error) → T、エラー時はpanic
func Get[T any](v T, err error) T
// must.Do: error → void、エラー時はpanic
func Do(err error)
加えて testing.T.Must[T any](v T, err error) T をテスト用に追加する案も議論された。
これによって何ができるようになるか
コード例
// Before: 従来の書き方(ボイラープレートが多い)
u, err := url.Parse("https://example.com/api")
if err != nil {
panic(err) // 定数URLなので実際には発生しない
}
var baseURL = u
// After: must.Get を使った書き方
var baseURL = must.Get(url.Parse("https://example.com/api"))
想定ユースケース:
init関数やパッケージレベル変数の初期化(URLやregexpなど定数値のパース)- 簡易スクリプトやCLIツールでのエラー処理省略
- テストコードでの前提条件セットアップ(テスト対象外の処理)
議論のハイライト
- 「小さすぎる」問題: 単一の極めてシンプルな関数のためだけに新パッケージを標準ライブラリに追加することへの抵抗感が根強かった。
github.com/searchで5,900件以上の独自実装が確認されたにもかかわらず、「標準ライブラリに入れる必要性」の合意が得られなかった testing.T.Mustへの懸念:adonovanが「これが追加されると、テストが失敗した際に有用なコンテキストを添えるという活性化エネルギーが上がる」と指摘。「このエラーは起きないはず」と「このエラーが起きないことをテストしている」の区別が曖昧になるmust.Doの誤用リスク:must.Do(process())のようにmain関数内でエラー処理代わりに使われることへの懸念。ianlancetaylorは「エラーハンドリング機構として使われるのは非常に残念」と発言- ジェネリックメソッド待ち: #77273(ジェネリックメソッド)の受理により
testing.T.Must[T any]が実現可能になったが、審査再開後もtesting.T.Must自体への懸念は解消されなかった - 元のプロポーザルへの回帰: 最終的にneilが「元々は
url.MustParseの提案だった」と原点回帰を促し、より限定的な #79946 として再検討が始まった