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

Go Proposal Weekly Digest

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

#80449active

go/types: add Scope.Elements iterator

新規提案

要約

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

概要

go/typesパッケージのScope型に対し、スコープ内のオブジェクト(識別子)を名前順に走査できるイテレータElements() iter.Seq[Object]を追加する提案です。既存のNames()+Lookup()による定型的なループを、Go 1.23で導入されたrange-over-funcを使ってより簡潔に書けるようにします。

ステータス変更

(新規)active
2026-08-20付でproposal reviewグループ(@aclements)により、週次のproposal reviewミーティングで審議される「active」列に追加されました。まだ承認や却下の最終判断が下されたわけではなく、今後の議論のステージに進んだ段階です。

技術的背景

現状の問題点

go/types.Scopeに格納されたオブジェクト(変数、関数、型など)を列挙する際、現在はScope.Names()でソート済みの名前一覧を取得し、各名前についてScope.Lookup(name)でオブジェクトを引く、という2段階の処理が必要です。

for _, name := range scope.Names() {
    obj := scope.Lookup(name)
    // objを使った処理
}

提案者(@adonovan)によれば、x/toolsリポジトリだけでもこのパターンが少なくとも29箇所で使われており、冗長かつミスを誘発しやすい定型コードになっています。

提案された解決策

ScopeElementsメソッドを追加し、iter.Seq[Object]型のイテレータを返すようにします。

package types // "go/types"
// Elements returns an iterator over the objects in s in name order.
//
// Example: for obj := range scope.Elements() { ... }
func (s *Scope) Elements() iter.Seq[Object]

内部実装は現状Names()の結果を使って各Objectyieldする単純なラッパーですが、パフォーマンス面の懸念(Names()はスライスの確保とソートを伴う)から、実装の詳細は議論の余地があります。また、イテレーション中にスコープが変更された場合の挙動について、コメントで「変更を禁止し、末尾で要素数が変化していればpanicする」という方針が提案されています。

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

go/typesを利用する静的解析ツールやコンパイラ関連ツール(x/tools配下のコマンド群など)で、スコープ内オブジェクトの列挙が1行のfor-range文で書けるようになります。

  • 静的解析ツール開発者: パッケージのトップレベル宣言や関数スコープの変数を走査するコードが簡潔になる
  • リネームツール・リファクタリングツール: cmd/bundlecmd/gorenameのような、スコープ内シンボルを一括処理するツールの実装が読みやすくなる
  • デッドコード検出ツール: cmd/deadcodeのように型宣言などをフィルタしながら走査する処理が簡潔になる

コード例

// Before: Names() と Lookup() を組み合わせた従来の書き方
for _, name := range scope.Names() {
    obj := scope.Lookup(name)
    if typeName, ok := obj.(*types.TypeName); ok {
        // ...
    }
}
// After: Elements イテレータを使った書き方
for obj := range scope.Elements() {
    if typeName, ok := obj.(*types.TypeName); ok {
        // ...
    }
}

議論のハイライト

  • 提案の動機は「重複コードの削減」であり、新しい機能追加というよりも既存APIの利便性向上を狙ったものです。
  • @mateusz834より、イテレーション中にスコープが変更された場合の挙動を仕様として明確化すべきという指摘があり、@adonovanは「変更を禁止し、要素数が変わっていれば末尾でpanicする」という方針で合意しました。
  • 提案本文中のTODOコメントでは、Names()が内部でソートを伴うためパフォーマンス上の懸念があり、順序を保証しない設計にすべきか検討されていましたが、提案者自身は「おそらく順序保証は維持すべき」と結論づけています。代替案として、ソート済み名前配列をキャッシュ(sync.Once等で初回生成後に保持)する最適化も言及されています。
  • 現時点ではproposal reviewミーティングでの審議段階(active)であり、実装方針やAPIの最終仕様は今後の議論で確定する見込みです。

関連リンク