メインコンテンツへスキップ

Go Proposal Weekly Digest

Go言語のproposal更新を毎週お届け

#80026declined

flag: add func (FlagSet) All() iter.Seq2\\[\\*Flag, bool]

ステータス変更: active declined

要約

AIによる要約であり、誤りを含む場合があります。

概要

flagパッケージに、全フラグを名前順に走査しつつ「値が設定されたか」を示す真偽値も同時に返すイテレータFlagSet.All() iter.Seq2[*Flag, bool]を追加する提案です。既存のVisit/VisitAllによるコールバック形式の走査を、Go 1.23で導入されたrange-over-func構文でシンプルに書けるようにすることが目的でした。

ステータス変更

activedeclined(重複による却下)
この提案は同種の提案である Issue #65675(flag: add All iterators and Flag.IsSet)と実質的に同一の内容であることが判明し、議論の実体は#65675側に一本化されました。#65675は先に提出されていたにもかかわらず一時停滞しており、本Issue(#80026)の方が先にproposal reviewのactiveカラムに載ったという経緯のねじれがありましたが、提案者自身(earthboundkid)が「#65675と同じ最終案」であると指摘し、aclementsが2026-07-01に本Issueを#65675の重複としてクローズ、2026-07-08に「新規性のある情報がないため議論を再開する必要はない」としてdeclined-as-duplicateが確定しました。

技術的背景

現状の問題点

現在のVisit(設定済みフラグのみ)やVisitAll(全フラグ)はコールバック関数を取るAPIのため、特定条件を満たす最初のフラグを探す、あるいは「設定済みか」を判定しながらループするといった処理では、外側スコープの変数(bool や error)をクロージャで書き換える回りくどいコードが必要でした。

var err error
cmdFlags.Visit(func(f *flag.Flag) {
    if globalFlags.Lookup(f.Name) == nil {
        err = fmt.Errorf("flag -%s belongs to subcommand but is placed before it", f.Name)
    }
})
if err != nil {
    return err
}

提案された解決策

iter.Seq2[*Flag, bool]を返すAll()メソッドを新設し、for f, set := rangeの形で全フラグと「設定済みか」を同時に取得できるようにする案でした。

func (f *FlagSet) All() iter.Seq2[*Flag, bool]

これによって何ができるようになるか

コールバックのネストや外部変数への副作用なしに、通常のfor文でフラグ集合を走査できるようになります。サブコマンド間でのフラグの誤配置検出、未設定フラグへの環境変数からのフォールバック設定、フラグ集合の絞り込み後の再実行処理など、複数の実用例が議論中に挙げられました。

コード例

// Before: コールバック + 外部変数によるワークアラウンド
var err error
cmdFlags.Visit(func(f *flag.Flag) {
    if globalFlags.Lookup(f.Name) == nil {
        err = fmt.Errorf("flag -%s belongs to subcommand but is placed before it", f.Name)
    }
})
// After: range-over-func によるシンプルな走査
for f, set := range cmdFlags.All() {
    if set && globalFlags.Lookup(f.Name) == nil {
        return fmt.Errorf("flag -%s belongs to subcommand but is placed before it", f.Name)
    }
}

議論のハイライト

  • jimmyfrascheはVisit相当のAllSet() iter.Seq[*Flag]も併設すべきかを提案したが、adonovanは「2番目の戻り値で設定済みかどうかが分かる以上、別イテレータは不要」として却下。
  • 実装上、mvdan(#65675側での議論)は「現状formal(全フラグ)とactual(設定済み)が別マップで管理されており、Seq2型のAPIは両マップの突き合わせが必要になる」と指摘。
  • 議論は最終的に「Flag構造体にIsSet boolフィールドを追加し、All()iter.Seq[*Flag]のみを返すシンプルな設計にすべき」という方向へ収束し、これは#65675側で継続検討されることになった。
  • 本Issue自体は技術的な当否ではなく、同一提案が並行して立てられていたことによるプロセス上の重複が理由で却下された点が特徴的(adonovan自身も「提案プロセスの一貫性・透明性の欠如」に言及)。

関連リンク