Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
range over func 2年間の軌跡 Issue #56413 はGoのエコシステムを...
Search
Ryuji Kokubu
September 11, 2026
Technology
110
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
range over func 2年間の軌跡 Issue #56413 はGoのエコシステムをどう変えたか
Go Conference2026にて登壇した内容になります
Ryuji Kokubu
September 11, 2026
More Decks by Ryuji Kokubu
See All by Ryuji Kokubu
大規模アプリケーションをリアーキテクトした際の知見
ryujicre8ive
1
1.3k
beerbash用_aws_re:invent参加レポ
ryujicre8ive
0
19
Other Decks in Technology
See All in Technology
コスト最適化の「めんどくさい」を AWS FinOps Agent でチョット楽にする
classmethod_kaz
0
320
Amazon Quick on DesktopがIAM Identity Centerで動かない理由
yukiogawa
0
170
The Agent Builder Loop from Daily Work to OSS
minorun365
PRO
3
140
山手線を徒歩で一周してわかった、 位置情報アプリは「足」が最強のデバッガー
hinakko
0
110
研究開発部の紹介 / Sansan R&D Profile
sansan33
PRO
5
25k
Where Is JetBrains AI Heading- — Central CLI, Air Alpha, and the Agentic Development Stack
x5gtrn
PRO
0
160
TinyGo 開発サイクルを高速化する:Go で作るエミュレータ入門
zozotech
PRO
1
650
20260912_スクラムにジェネラリストは必要か
ryugen04
0
370
module Synths; end
asonas
1
130
ASTを使って影響範囲を特定する
nealle
0
170
Gitは怖い?共有ワークスペースから始めるSnowflakeチーム開発
coco_se
0
180
Adaptive Warehouse を今すぐ導入すべき理由と迷ったときの判断基準
__allllllllez__
0
200
Featured
See All Featured
The Spectacular Lies of Maps
axbom
PRO
1
990
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
500
Bash Introduction
62gerente
615
220k
YesSQL, Process and Tooling at Scale
rocio
174
15k
Mind Mapping
helmedeiros
1
350
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
230
23k
Automating Front-end Workflow
addyosmani
1369
210k
sira's awesome portfolio website redesign presentation
elsirapls
0
410
For a Future-Friendly Web
brad_frost
183
10k
Odyssey Design
rkendrick25
PRO
2
800
AI Search: Where Are We & What Can We Do About It?
aleyda
0
7.9k
A designer walks into a library…
pauljervisheath
211
25k
Transcript
range over func 2年間の軌跡 Issue #56413 はGoのエコシステムをどう変えたか 合同会社DMM.com / オンラインサロン開発部
國分竜二 2026 / 09 / 11 © DMM.com
自己紹介 • 合同会社DMM.com オンライン サロン開発部 • 今日ブースも出してるのでぜひ 遊びに来てください(もう終わり ですが...) •
X: @_ryuji_cre8ive © DMM.com
range over funcについての確認 会場の皆さんにアンケートを取りたいと思います © DMM.com
range over funcについての確認 会場の皆さんにアンケートを取りたいと思います 手を挙げて答えてください © DMM.com
range over funcについての確認 初めて聞いた🖐 © DMM.com
range over funcについての確認 知ってるよ🖐 © DMM.com
range over funcについての確認 使ってるよ🖐 © DMM.com
range over funcについての確認 ご協力ありがとうご ざいます🫶 © DMM.com
改めて復習 • range over func とは? • 関数値を range で反復する仕
組み • Go 1.23 で正式導入 • iter.Seq / iter.Seq2 を range で 反復 for v := range seq { use(v) } for k, v := range seq2 { use(k, v) } © DMM.com
閑話休題 © DMM.com
range over func 2年間の軌跡 Issue #56413 はGoのエコシステムをどう変えたか 合同会社DMM.com / オンラインサロン開発部
國分竜二 2026 / 09 / 11 © DMM.com
この3つ、なぜ全部シグネチャが違うんでしょう? filepath.Walk( func(path string, info fs.FileInfo, err error) error, )
sync.Map.Range( func(key, value any) bool, ) flag.Visit( func(f *flag.Flag), ) © DMM.com
この3つ、なぜ全部シグネチャが違うんでしょう? filepath.Walk( func(path string, info fs.FileInfo, err error) error, )
sync.Map.Range( func(key, value any) bool, ) flag.Visit( func(f *flag.Flag), ) © DMM.com どれもとあるコレクションを走 査するメソッドです
この3つ、なぜ全部シグネチャが違うんでしょう? filepath.Walk( func(path string, info fs.FileInfo, err error) error, )
やりたいことは同じ。 func(key, それなのに呼び出し方と戻り値はバラバラ value any) bool, sync.Map.Range( ) flag.Visit( func(f *flag.Flag), ) © DMM.com どれもとあるコレクションを走 査するメソッドです
CHAPTER 1 戦国時代 Why a common iteration protocol was needed
© DMM.com
標準ライブラリの走査APIは、形が揃っていない 共通の interface はなく、呼び出し方も戻り値もバラバラ • • • • • Frames.Next
(T, bool) Scanner.Scan bool sql.Rows.Next bool + Err filepath.Walk(root, fn) sync.Map.Range(fn) © DMM.com
同じ (T, bool) でも意味が違う // 多くの慣習: bool は「Tが有効かどうか」 v, ok
:= m[key] // okがtrueならvは有効 // runtime.Frames.Next は違う frame, more := frames.Next() // more は「次の呼び出しが有効な値を返すか」 © DMM.com
同じ (T, bool) でも意味が違う // 多くの慣習: bool は「Tが有効かどうか」 v, ok
:= m[key] // okがtrueならvは有効 // runtime.Frames.Next は違う frame, more := frames.Next() // more は「次の呼び出しが有効な値を返すか」 同じ形をしていても、中身の意味は関数ごとに学び直す必要があった。 © DMM.com
2022年10月25日、議論が動き出す Discussion #56413 “user-defined iteration using range over func values”
© DMM.com なぜ動き出したか
2022年10月25日、議論が動き出す Discussion #56413 なぜ動き出したか “user-defined iteration using range over func
values” Goにはシーケンシャルなデータを反復処理する標 © DMM.com 準的な方法がなかった。各実装が個別最適化し た結果、Goユーザーのキャッチアップコストが増 大していた。
実際の議論を見てみる 「標準的な iteration がない」 という問題意識から range over func の議論が始 まりました
© DMM.com
実験から正式リリースまでの時系列 2022.10 Discussion #56413 オープン © DMM.com → 2023.07 Issue
#61405 提案提出 → Go 1.22 GOEXPERIMENT=rangefunc で試験導入 → Go 1.23 2024.08 正式リリース 言語機能として有効化
CHAPTER 2 設計の決断 Why a function type, not an interface
© DMM.com
設計の決断 みなさんなら、 interfaceで解決しませんか? type Iterator[T any] interface { Next() (T,
bool) } // でもGoチームはこの道を選ばなかった © DMM.com
設計の決断 みなさんなら、 interfaceで解決しませんか? type Iterator[T any] interface { Next() (T,
bool) } // でもGoチームはこの道を選ばなかった 答えは、言語仕様そのものへの組み込みでした。 © DMM.com
Issue #61405 — rsc、2023年7月17日 “spec: add range over int, range
over func” Discussion #56413 の議論を受けて、 for-range で整数と関数を扱えるようにする 言語拡張として提案が出された © DMM.com 11
Issue #61405 — rsc、2023年7月17日 “spec: add range over int, range
over func” Discussion #56413 の議論を受けて、 for-range で整数と関数を扱えるようにする 言語拡張として提案が出された push-iteratorのみを言語サポートの 対象にし、pull-iteratorへの変換は 別の標準ライブラリ関数に委ねる、 という役割分担を明確化した。 出典 : golang/go©Issue #61405 DMM.com 11
Issue #61405 — rsc、2023年7月17日 “spec: add range over int, range
over func” Push? Pull? Discussion #56413 の議論を受けて、 for-range で整数と関数を扱えるようにする 言語拡張として提案が出された push-iteratorのみを言語サポートの 対象にし、pull-iteratorへの変換は 別の標準ライブラリ関数に委ねる、 という役割分担を明確化した。 出典 : golang/go©Issue #61405 DMM.com 11
Push と Pull:誰が次の1件を主導するか Push Iterator © DMM.com
Push と Pull:誰が次の1件を主導するか Push Iterator yieldを呼び出し、値を mainにpush © DMM.com
Push と Pull:誰が次の1件を主導するか Pull Iterator Push Iterator yieldを呼び出し、値を mainにpush ©
DMM.com
Push と Pull:誰が次の1件を主導するか Pull Iterator Push Iterator yieldを呼び出し、値を mainにpush main側が明示的に
次の値を呼び出す next関数を実行 © DMM.com
Push と Pull:誰が次の1件を主導するか Pull Iterator Push Iterator Push / Pullは「値の向き」ではなく
yieldを呼び出し、値を iterationの主導権がどちらにあるかを表します mainにpush main側が明示的に 次の値を呼び出す next関数を実行 © DMM.com
range over funcは、どうやって動く? “For a function f, the iteration proceeds
by calling f with a synthesized yield function that invokes the body of the loop.” 関数 f の反復は、ループ本体を呼び出す合成された yield 関数を渡して、f を呼び出すことで進む。 © DMM.com
range over funcは、どうやって動く? “For a function f, the iteration proceeds
by calling f with a synthesized yield function that invokes the body of the loop.” 関数 f の反復は、ループ本体を呼び出す合成された yield 関数を渡して、f を呼び出すことで進む。 コンパイラが yield関数を合成し、 range本体へ渡している。 © DMM.com
rangeの中のdeferは、いつ実行される? for v := range seq { defer cleanup(v) …
} © DMM.com
rangeの中のdeferは、いつ実行される? for v := range seq { defer cleanup(v) …
} © DMM.com 1回ごとにdefer?
rangeの中のdeferは、いつ実行される? for v := range seq { defer cleanup(v) …
} 1回ごとにdefer? 答え:外側の関数が returnするとき。他の rangeループと同じ © DMM.com
CHAPTER 3 標準ライブラリの変化 What actually changed in the stdlib ©
DMM.com
ソート済みmap を走査する BEFORE © DMM.com
ソート済みmap を走査する BEFORE ①sに要素を append © DMM.com
ソート済みmap を走査する BEFORE ①sに要素を append ②配列sをソート © DMM.com
ソート済みmap を走査する BEFORE ①sに要素を append ②配列sをソート ③出力 © DMM.com
ソート済みmap を走査する BEFORE ①sに要素を append コードが長い ... ②配列sをソート ③出力 ©
DMM.com
ソート済みmap を走査する BEFORE © DMM.com AFTER
ソート済みmap を走査する AFTER BEFORE ①キーを返す iter func © DMM.com
ソート済みmap を走査する AFTER BEFORE ①キーを返す iter func ②iterを受け取りソー トされた配列で返す ©
DMM.com
ソート済みmap を走査する AFTER BEFORE ①キーを返す iter func ②iterを受け取りソー トされた配列で返す ③出力
© DMM.com
ソート済みmap を走査する AFTER BEFORE ①キーを返す iter func たった3行に...! ②iterを受け取りソー トされた配列で返す
③出力 © DMM.com
固定回数のループ・逆順走査 BEFORE for i := 0; i < n; i++
{ /* ... */ } for i := n-1; i >= 0; i-- { _ = s[i] } © DMM.com
固定回数のループ・逆順走査 BEFORE for i := 0; i < n; i++
{ /* ... */ } ①よくあるforループ for i := n-1; i >= 0; i-- { _ = s[i] } © DMM.com
固定回数のループ・逆順走査 BEFORE for i := 0; i < n; i++
{ /* ... */ } ①よくあるforループ for i := n-1; i >= 0; i-- { _ = s[i] } © DMM.com ②逆順にした途端 あれ、条件は? イテレーションの向きは?
固定回数のループ・逆順走査 BEFORE for i := 0; i < n; i++
{ /* ... */ } ①よくあるforループ パニック for i := n-1; i >= 0; i-- { _ = s[i] } © DMM.com ②逆順にした途端 あれ、条件は? イテレーションの向きは?
固定回数のループ・逆順走査 BEFORE AFTER for i := 0; i < n;
i++ { /* ... */ } for i := range n { for i := n-1; i >= 0; i-- { _ = s[i] } for i, v := range © DMM.com // ... } slices.Backward(s) { // ... }
固定回数のループ・逆順走査 BEFORE AFTER for i := 0; i < 便利な関数
n; i++ { /* ... */ } Backward登場 for i := range n { for i := n-1; i >= 0; i-- { _ = s[i] } for i, v := range © DMM.com // ... } slices.Backward(s) { // ... }
固定回数のループ・逆順走査 BEFORE for i := 0; i < 便利な関数 n;
i++ { /* ... */ } Backward登場 for i := n-1; i >= 0; i-- { _ = s[i] } © DMM.com AFTER for i := range n { // ... �� } for i, v := range slices.Backward(s) { // ... }
maps.Keys / Values は、なぜ iterator になった? 2021.07 #47330 maps 構想
Keys / Values →sliceを返す © DMM.com
maps.Keys / Values は、なぜ iterator になった? 2021.07 #47330 2022.12 #57436
maps 構想 Keys / Values →sliceを返す Go 1.21向けに x/exp/maps 標準化を提案 © DMM.com
maps.Keys / Values は、なぜ iterator になった? iter構想 2021.07 #47330 2022.12
#57436 maps 構想 Keys / Values →sliceを返す Go 1.21向けに x/exp/maps 標準化を提案 © DMM.com
Go 1.21でslice版を出すのは早い? Go 1.22でiteratorを返す可能性が高いなら、 Go 1.21でsliceを返す形で出すのは短絡的では ないか。 いったん取り下げるべきでは? 将来、iteratorとしてMap /
Filter / Reduceと 組み合わせる可能性がある。 sliceが必要なら slices.Collect で変換できる。 © DMM.com
maps.Keys / Values は、なぜ iterator になった? iter構想 2021.07 #47330 2022.12
#57436 2023.07 #61538 maps 構想 Keys / Values →sliceを返す Go 1.21向けに x/exp/maps 標準化を提案 slice版を見送り © DMM.com KeysSlice案も 不採用#61626
maps.Keys / Values は、なぜ iterator になった? iter構想 2021.07 #47330 2022.12
#57436 2023.07 #61538 2023.08 #61900 maps 構想 Keys / Values →sliceを返す Go 1.21向けに x/exp/maps 標準化を提案 slice版を見送り iter.Seqを追加 Keys / Values Go 1.23 © DMM.com KeysSlice案も 不採用#61626
maps.Keys / Values は、なぜ iterator になった? iter構想 2021.07 #47330 2022.12
#57436 2023.07 #61538 2023.08 #61900 maps 構想 Keys / Values →sliceを返す Go 1.21向けに x/exp/maps 標準化を提案 slice版を見送り iter.Seqを追加 Keys / Values Go 1.23 KeysSlice案も 不採用#61626 共通のiteration protocolができたことで、 APIの戻り値だけでなく、名前の使い方にまで影響を及ぼした © DMM.com
パフォーマンスはどう変わったか(実測) 共通条件:1M items / Go 1.23.1 / M4 Pro 全件処理(時間
/ メモリ/ 確保回数) 早期終了(時間 / メモリ/ 確保回数) Slice 63.1ms / 8.0MB / 1 alloc 6.78ms / 8.0MB / 1 alloc Iter 64.7ms / 41.7MB / 41 allocs 3.43ms / 0B / 0 allocs 指標 © DMM.com
パフォーマンスはどう変わったか(実測) 共通条件:1M items / Go 1.23.1 / M4 Pro 全件処理(時間
/ メモリ/ 確保回数) 早期終了(時間 / メモリ/ 確保回数) Slice 63.1ms / 8.0MB / 1 alloc 6.78ms / 8.0MB / 1 alloc Iter 64.7ms / 41.7MB / 41 allocs 3.43ms / 0B / 0 allocs 指標 Iterはわずかに不 利 © DMM.com
パフォーマンスはどう変わったか(実測) 共通条件:1M items / Go 1.23.1 / M4 Pro 全件処理(時間
/ メモリ/ 確保回数) 早期終了(時間 / メモリ/ 確保回数) Slice 63.1ms / 8.0MB / 1 alloc 6.78ms / 8.0MB / 1 alloc Iter 64.7ms / 41.7MB / 41 allocs 3.43ms / 0B / 0 allocs 指標 Iterはわずかに不 利 © DMM.com Iter が約2倍高速
パフォーマンスはどう変わったか(実測) 共通条件:1M items / Go 1.23.1 / M4 Pro 指標
Slice Iter 全件処理(時間 / メモリ/ 確保回数) 早期終了(時間 / メモリ/ 確保回数) 63.1ms / 8.0MB / 1 alloc 6.78ms / 8.0MB / 1 alloc 64.7ms / 41.7MB / 41 allocs 3.43ms / 0B / 0 allocs 早期終了できるようなケースでは 圧倒的に高パフォーマンス Iterはわずかに不 利 © DMM.com Iter が約2倍高速
iterator化されなかったAPIもある os.ReadDir / filepath.Glob すべての APIがiterator向き とは限らない © DMM.com なぜ?
• APIはソート済みの結果を返す仕様。 • 全件を先に集める必要がある。 • 早期終了とメモリ節約が効かない。
CHAPTER 4 OSSエコシステムの変化 How the community responded © DMM.com
xiterの提案は、どうなった? 2023.08 xiter 提案 ・Map ・Concat ・Equal …etc © DMM.com
xiterの提案は、どうなった? 2023.08 2024.07 xiter 提案 ・Map ・Concat ・Equal …etc Go
1.23対応 仕様に合わせ てxiter更新 © DMM.com
xiterの提案は、どうなった? 2023.08 2024.07 Go 1.23 xiter 提案 ・Map ・Concat ・Equal
…etc Go 1.23対応 仕様に合わせ てxiter更新 iter、標準ライ ブラリへ © DMM.com
xiterの提案は、どうなった? 2023.08 2024.07 Go 1.23 xiter 提案 ・Map ・Concat ・Equal
…etc Go 1.23対応 仕様に合わせ てxiter更新 iter、標準ライ ブラリへ © DMM.com 現在 not planned (お見送り)
xiterの提案は、どうなった? 2023.08 2024.07 Go 1.23 xiter 提案 ・Map ・Concat ・Equal
…etc Go 1.23対応 仕様に合わせ てxiter更新 iter、標準ライ ブラリへ 現在 not planned (お見送り) 見送り理由 →標準に入れるほど共通の使い道がまだ見えていない © DMM.com
sqlc: iterator API は今も議論中 Seq + Err() ループ内の err は不要
© DMM.com Seq2[T, error]
sqlc: iterator API は今も議論中 Seq + Err() ループ内の err は不要
ループ内の err は不要 © DMM.com Seq2[T, error]
sqlc: iterator API は今も議論中 Seq + Err() ループ内の err は不要
ループ内の err は不要 © DMM.com Seq2[T, error]
sqlc: iterator API は今も議論中 Seq + Err() Seq2[T, error] ループ内の
err は不要 ループ内の err は不要 iteration中のエラーは返せる ただし、break後のClose()エラーをどのように利 用側に返すかは別問題 © DMM.com
sqlc: iterの議論は終わらなかった 2024.10 #3631 iterator API Seq+Err vs Seq2 ©
DMM.com
sqlc: iterの議論は終わらなかった 2024.10 #3631 2025.09 #4108 iterator API Seq+Err vs
Seq2 APIを決めず helperに限定 © DMM.com
sqlc: iterの議論は終わらなかった 2024.10 #3631 2025.09 #4108 2026.06 #4488 iterator API
Seq+Err vs Seq2 APIを決めず helperに限定 Seq2を試す opt-in PoC © DMM.com
sqlc: iterの議論は終わらなかった 2024.10 #3631 2025.09 #4108 2026.06 #4488 iterator API
Seq+Err vs Seq2 APIを決めず helperに限定 Seq2を試す opt-in PoC →sqlcのiterator APIはまだ決定版に至っていない。 range over funcで反復は共通化できても、共通の protocolだけでは、ドメイ ン固有のライフサイクル設計までは解決できない。 © DMM.com
実際に動いているOSS実装 go-simpler.org/queries // go-simpler.org/queries func Query[T any]( ctx context.Context, q
Querier, query string, args ...any, ) iter.Seq2[T, error] for row, err := range queries.Query[Order](ctx, db, sql) { if err != nil { return err } } Close や defer を利用側が意識しなくていい設計に! © DMM.com
比較 go-simpler sqlc ライブラリが責任を引き受ける 生成APIとして契約を決める必要がある エラーは基本的に致命的。そこで停止 エラーの扱い方自体を検討中 Closeは利用者から隠す Closeやbreak時の扱いも設計対象 狭い用途に対して意見を決めやすい
多くの利用者・既存コードへの影響が大きい © DMM.com
比較 go-simpler sqlc ライブラリが責任を引き受ける 生成APIとして契約を決める必要がある Closeは利用者から隠す Closeやbreak時の扱いも設計対象 go-simpler:Closeとエラー処理をライブラリ 側で引き受ける設計を選んだ。 エラーは基本的に致命的。そこで停止
エラーの扱い方自体を検討中 sqlc:生成APIとしてどこまで利用者に委ね 狭い用途に対して意見を決めやすい 多くの利用者・既存コードへの影響が大きい るかを決める必要がある。 © DMM.com
CHAPTER 5 2年経った今、どう使う? From observation to your own code ©
DMM.com
[]T を返すか、iter.Seq を返すか 複数回イテレーションする → []T 全件が必要(ソート・集計など) → []T 1回限りのストリーム
→ iter.Seq 早期終了の効果が大きい → iter.Seq 置き換え関係ではない。呼び出し側の利用特性で選ぶ。 © DMM.com
今日の Before / After を、自分 のコードへ 観察者として追った2年間。次はあなたの番です。 © DMM.com
Thank you! • • • • • Discussion #56413 github.com/golang/go/discussions/56413
Issue #61405 github.com/golang/go/issues/61405 Issue #61898 github.com/golang/go/issues/61898 sqlc PR #3631 github.com/sqlc-dev/sqlc/pull/3631 Go Wiki go.dev/wiki/RangefuncExperiment ご清聴ありがとうございました © DMM.com