Go 1.24イテレータ応用:range over func深度実践 2026

编程语言

Go 1.24イテレータ応用:range over func深度実践

Go 1.22でrange over intが導入され、Go 1.23でrange over funcが導入——Goについに「ファーストクラス」のイテレータが誕生しました。しかし多くのGopherはまだfor i, v := range sliceの段階にとどまり、range over funcの理解は標準ライブラリのslicesmapsパッケージに限定されています。

Go 1.24に至り、イテレータエコシステムは成熟しました:ジェネリックイテレータ、イテレータ合成、遅延評価パイプライン……これらのパターンにより、Goコードはよりエレガントに、より効率的に、よりGo-idiomaticになります。本記事では5つのコアパターンから、Goイテレータを徹底マスターします。

コア概念早見表

概念 説明 シグネチャ
イテレータ関数 rangeで反復可能な関数型 func(yield func(V) bool)
インデックス付きイテレータ インデックスと値を同時に返す func(yield func(int, V) bool)
Pullイテレータ 手動で次の値を取得 func() (V, bool)
Pushイテレータ yieldコールバックに値をプッシュ func(yield func(V) bool)
イテレータ合成 複数イテレータの直列/並列接続 func(...Iter) Iter
遅延評価 実際に消費されるまで計算を遅延 イテレータは天然の遅延評価

Goイテレータの5つのペインポイント

  1. カスタムコレクションの走査が煩雑:ツリー、グラフ、リンクリストなどは手動でコールバックを書く必要があり、コードが醜い
  2. パイプライン式データ処理の欠如:Pythonジェネレータのようなfilter/mapチェーンができない
  3. ジェネリックイテレータ型の複雑さfunc(yield func(V) bool)のシグネチャが初心者には難しい
  4. イテレータとgoroutineの相互作用:並行イテレータの正しい使用パターンが不明確
  5. Pull vs Pushの選択困難:2つのイテレータモードの使い分けが不明確

パターン1:range over func基礎

Go 1.23で導入された3つのイテレータ関数シグネチャは、すべてを理解する基礎です。

// go-iterator-basics/main.go
// 実行環境: Go 1.24+ / 追加依存なし
package main

import (
	"fmt"
	"iter"
)

// Range 整数シーケンスイテレータを生成
func Range(n int) iter.Seq[int] {
	return func(yield func(int) bool) {
		for i := range n {
			if !yield(i) {
				return
			}
		}
	}
}

// RangeWithStep ステップ付き整数シーケンス
func RangeWithStep(start, end, step int) iter.Seq[int] {
	return func(yield func(int) bool) {
		for i := start; i < end; i += step {
			if !yield(i) {
				return
			}
		}
	}
}

// Enumerate 任意のスライスにインデックスを追加
func Enumerate[T any](items []T) iter.Seq2[int, T] {
	return func(yield func(int, T) bool) {
		for i, item := range items {
			if !yield(i, item) {
				return
			}
		}
	}
}

// Take 最初のn個の要素のみ取得
func Take[T any](n int, seq iter.Seq[T]) iter.Seq[T] {
	return func(yield func(T) bool) {
		count := 0
		for v := range seq {
			if count >= n {
				return
			}
			if !yield(v) {
				return
			}
			count++
		}
	}
}

// ToPull PushイテレータをPullイテレータに変換
func ToPull[T any](seq iter.Seq[T]) func() (T, bool) {
	next, stop := iter.Pull(seq)
	return func() (T, bool) {
		v, ok := next()
		return v, ok
	}
}

func main() {
	fmt.Println("=== 基本イテレータ ===")
	for i := range Range(5) {
		fmt.Print(i, " ") // 0 1 2 3 4
	}
	fmt.Println()

	fmt.Println("=== ステップ付き ===")
	for i := range RangeWithStep(0, 20, 5) {
		fmt.Print(i, " ") // 0 5 10 15
	}
	fmt.Println()

	fmt.Println("=== インデックス付き ===")
	fruits := []string{"りんご", "バナナ", "みかん"}
	for i, fruit := range Enumerate(fruits) {
		fmt.Printf("%d: %s  ", i, fruit)
	}
	fmt.Println()

	fmt.Println("=== 早期終了 ===")
	for v := range Take(3, Range(100)) {
		fmt.Print(v, " ") // 0 1 2
	}
	fmt.Println()

	fmt.Println("=== Pullイテレータ ===")
	pull := ToPull(Range(3))
	for {
		v, ok := pull()
		if !ok {
			break
		}
		fmt.Print(v, " ") // 0 1 2
	}
	fmt.Println()
}

パターン2:ジェネリックイテレータ

ジェネリクスによりイテレータは真の「ファーストクラス市民」に——1つのFilter関数で任意の型のシーケンスをフィルタリングできます。

// go-generic-iterator/main.go
// 実行環境: Go 1.24+ / 追加依存なし
package main

import (
	"fmt"
	"iter"
	"strings"
)

// Filter シーケンスの要素をフィルタリング
func Filter[T any](seq iter.Seq[T], predicate func(T) bool) iter.Seq[T] {
	return func(yield func(T) bool) {
		for v := range seq {
			if predicate(v) {
				if !yield(v) {
					return
				}
			}
		}
	}
}

// Map シーケンスの各要素を変換
func Map[T any, R any](seq iter.Seq[T], transform func(T) R) iter.Seq[R] {
	return func(yield func(R) bool) {
		for v := range seq {
			if !yield(transform(v)) {
				return
			}
		}
	}
}

// FlatMap 各要素を変換後にフラット化
func FlatMap[T any, R any](seq iter.Seq[T], transform func(T) iter.Seq[R]) iter.Seq[R] {
	return func(yield func(R) bool) {
		for v := range seq {
			for r := range transform(v) {
				if !yield(r) {
					return
				}
			}
		}
	}
}

// Reduce シーケンスを単一値に還元
func Reduce[T any, R any](seq iter.Seq[T], initial R, accumulator func(R, T) R) R {
	result := initial
	for v := range seq {
		result = accumulator(result, v)
	}
	return result
}

// Chunk シーケンスを固定サイズのグループに分割
func Chunk[T any](size int, seq iter.Seq[T]) iter.Seq[[]T] {
	return func(yield func([]T) bool) {
		chunk := make([]T, 0, size)
		for v := range seq {
			chunk = append(chunk, v)
			if len(chunk) == size {
				if !yield(chunk) {
					return
				}
				chunk = make([]T, 0, size)
			}
		}
		if len(chunk) > 0 {
			yield(chunk)
		}
	}
}

// Distinct 重複除去
func Distinct[T comparable](seq iter.Seq[T]) iter.Seq[T] {
	return func(yield func(T) bool) {
		seen := make(map[T]bool)
		for v := range seq {
			if !seen[v] {
				seen[v] = true
				if !yield(v) {
					return
				}
			}
		}
	}
}

func main() {
	numbers := slicesToIter([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})

	evens := Filter(numbers, func(n int) bool { return n%2 == 0 })
	squares := Map(evens, func(n int) int { return n * n })
	first3 := Take(3, squares)

	fmt.Print("チェーン操作: ")
	for v := range first3 {
		fmt.Print(v, " ") // 4 16 36
	}
	fmt.Println()

	sum := Reduce(slicesToIter([]int{1, 2, 3, 4, 5}), 0,
		func(acc, n int) int { return acc + n })
	fmt.Println("合計:", sum) // 15

	fmt.Print("チャンク: ")
	for chunk := range Chunk(3, slicesToIter([]int{1, 2, 3, 4, 5, 6, 7})) {
		fmt.Print(chunk, " ")
	}
	fmt.Println()

	fmt.Print("重複除去: ")
	for v := range Distinct(slicesToIter([]string{"go", "rust", "go", "python", "rust"})) {
		fmt.Print(v, " ")
	}
	fmt.Println()
}

func slicesToIter[T any](s []T) iter.Seq[T] {
	return func(yield func(T) bool) {
		for _, v := range s {
			if !yield(v) {
				return
			}
		}
	}
}

パターン3:ツリー/グラフ探索イテレータ

イテレータの最も強力な応用シナリオ——再帰探索を合成可能なパイプラインに変換。

// go-tree-iterator/main.go
// 実行環境: Go 1.24+ / 追加依存なし
package main

import (
	"fmt"
	"iter"
)

type TreeNode[T any] struct {
	Value T
	Left  *TreeNode[T]
	Right *TreeNode[T]
}

// InOrder 順序通り走査イテレータ(左-根-右)
func (n *TreeNode[T]) InOrder() iter.Seq[T] {
	return func(yield func(T) bool) {
		n.inOrderHelper(yield)
	}
}

func (n *TreeNode[T]) inOrderHelper(yield func(T) bool) bool {
	if n == nil {
		return true
	}
	if !n.Left.inOrderHelper(yield) {
		return false
	}
	if !yield(n.Value) {
		return false
	}
	if !n.Right.inOrderHelper(yield) {
		return false
	}
	return true
}

// PreOrder 行きがけ走査イテレータ(根-左-右)
func (n *TreeNode[T]) PreOrder() iter.Seq[T] {
	return func(yield func(T) bool) {
		n.preOrderHelper(yield)
	}
}

func (n *TreeNode[T]) preOrderHelper(yield func(T) bool) bool {
	if n == nil {
		return true
	}
	if !yield(n.Value) {
		return false
	}
	if !n.Left.preOrderHelper(yield) {
		return false
	}
	if !n.Right.preOrderHelper(yield) {
		return false
	}
	return true
}

// LevelOrder レベル順走査イテレータ(BFS)
func (n *TreeNode[T]) LevelOrder() iter.Seq[T] {
	return func(yield func(T) bool) {
		if n == nil {
			return
		}
		queue := []*TreeNode[T]{n}
		for len(queue) > 0 {
			current := queue[0]
			queue = queue[1:]
			if !yield(current.Value) {
				return
			}
			if current.Left != nil {
				queue = append(queue, current.Left)
			}
			if current.Right != nil {
				queue = append(queue, current.Right)
			}
		}
	}
}

// Graph グラフ定義
type Graph[T comparable] struct {
	adjList map[T][]T
}

func NewGraph[T comparable]() *Graph[T] {
	return &Graph[T]{adjList: make(map[T][]T)}
}

func (g *Graph[T]) AddEdge(from, to T) {
	g.adjList[from] = append(g.adjList[from], to)
}

// DFS 深さ優先探索イテレータ
func (g *Graph[T]) DFS(start T) iter.Seq[T] {
	return func(yield func(T) bool) {
		visited := make(map[T]bool)
		g.dfsHelper(start, visited, yield)
	}
}

func (g *Graph[T]) dfsHelper(node T, visited map[T]bool, yield func(T) bool) bool {
	if visited[node] {
		return true
	}
	visited[node] = true
	if !yield(node) {
		return false
	}
	for _, neighbor := range g.adjList[node] {
		if !g.dfsHelper(neighbor, visited, yield) {
			return false
		}
	}
	return true
}

// BFS 幅優先探索イテレータ
func (g *Graph[T]) BFS(start T) iter.Seq[T] {
	return func(yield func(T) bool) {
		visited := make(map[T]bool)
		queue := []T{start}
		visited[start] = true
		for len(queue) > 0 {
			node := queue[0]
			queue = queue[1:]
			if !yield(node) {
				return
			}
			for _, neighbor := range g.adjList[node] {
				if !visited[neighbor] {
					visited[neighbor] = true
					queue = append(queue, neighbor)
				}
			}
		}
	}
}

func main() {
	root := &TreeNode[int]{
		Value: 4,
		Left:  &TreeNode[int]{Value: 2, Left: &TreeNode[int]{Value: 1}, Right: &TreeNode[int]{Value: 3}},
		Right: &TreeNode[int]{Value: 6, Left: &TreeNode[int]{Value: 5}, Right: &TreeNode[int]{Value: 7}},
	}

	fmt.Print("順序通り: ")
	for v := range root.InOrder() { fmt.Print(v, " ") } // 1 2 3 4 5 6 7
	fmt.Println()

	fmt.Print("行きがけ: ")
	for v := range root.PreOrder() { fmt.Print(v, " ") } // 4 2 1 3 6 5 7
	fmt.Println()

	fmt.Print("レベル順: ")
	for v := range root.LevelOrder() { fmt.Print(v, " ") } // 4 2 6 1 3 5 7
	fmt.Println()

	g := NewGraph[string]()
	g.AddEdge("A", "B")
	g.AddEdge("A", "C")
	g.AddEdge("B", "D")
	g.AddEdge("C", "D")
	g.AddEdge("D", "E")

	fmt.Print("DFS: ")
	for v := range g.DFS("A") { fmt.Print(v, " ") }
	fmt.Println()

	fmt.Print("BFS: ")
	for v := range g.BFS("A") { fmt.Print(v, " ") }
	fmt.Println()
}

パターン4:イテレータ合成とパイプライン

イテレータの最もエレガントな使い方——Unixパイプのようにデータ処理フローを合成。

// go-iterator-pipeline/main.go
// 実行環境: Go 1.24+ / 追加依存なし
package main

import (
	"fmt"
	"iter"
	"strings"
)

// Concat 複数イテレータを連結
func Concat[T any](seqs ...iter.Seq[T]) iter.Seq[T] {
	return func(yield func(T) bool) {
		for _, seq := range seqs {
			for v := range seq {
				if !yield(v) { return }
			}
		}
	}
}

// TakeWhile 条件がtrueの間値を取得
func TakeWhile[T any](seq iter.Seq[T], predicate func(T) bool) iter.Seq[T] {
	return func(yield func(T) bool) {
		for v := range seq {
			if !predicate(v) { return }
			if !yield(v) { return }
		}
	}
}

// DropWhile 条件がtrueの要素をスキップ
func DropWhile[T any](seq iter.Seq[T], predicate func(T) bool) iter.Seq[T] {
	return func(yield func(T) bool) {
		dropping := true
		for v := range seq {
			if dropping && predicate(v) { continue }
			dropping = false
			if !yield(v) { return }
		}
	}
}

// ログ処理パイプライン
type LogEntry struct {
	Timestamp string
	Level     string
	Message   string
}

func ParseLogs(rawLines iter.Seq[string]) iter.Seq[LogEntry] {
	return Map(rawLines, func(line string) LogEntry {
		parts := strings.SplitN(line, " ", 3)
		if len(parts) < 3 { return LogEntry{Message: line} }
		return LogEntry{Timestamp: parts[0], Level: parts[1], Message: parts[2]}
	})
}

func FilterByLevel(level string, logs iter.Seq[LogEntry]) iter.Seq[LogEntry] {
	return Filter(logs, func(l LogEntry) bool { return l.Level == level })
}

func ExtractMessages(logs iter.Seq[LogEntry]) iter.Seq[string] {
	return Map(logs, func(l LogEntry) string { return l.Message })
}

func main() {
	fmt.Print("連結: ")
	for v := range Concat(slicesToIter([]int{1, 2, 3}), slicesToIter([]int{4, 5, 6})) {
		fmt.Print(v, " ")
	}
	fmt.Println()

	rawLogs := slicesToIter([]string{
		"2026-01-01 ERROR データベース接続失敗",
		"2026-01-01 INFO サービス起動",
		"2026-01-01 ERROR キャッシュタイムアウト",
		"2026-01-01 WARN メモリ使用率高",
	})

	fmt.Println("\n=== ログパイプライン:ERRORメッセージのみ ===")
	for msg := range ExtractMessages(FilterByLevel("ERROR", ParseLogs(rawLogs))) {
		fmt.Println("  ", msg)
	}
}

func slicesToIter[T any](s []T) iter.Seq[T] {
	return func(yield func(T) bool) {
		for _, v := range s { if !yield(v) { return } }
	}
}

func Filter[T any](seq iter.Seq[T], predicate func(T) bool) iter.Seq[T] {
	return func(yield func(T) bool) {
		for v := range seq {
			if predicate(v) { if !yield(v) { return } }
		}
	}
}

func Map[T any, R any](seq iter.Seq[T], transform func(T) R) iter.Seq[R] {
	return func(yield func(R) bool) {
		for v := range seq { if !yield(transform(v)) { return } }
	}
}

func Take[T any](n int, seq iter.Seq[T]) iter.Seq[T] {
	return func(yield func(T) bool) {
		count := 0
		for v := range seq {
			if count >= n { return }
			if !yield(v) { return }
			count++
		}
	}
}

パターン5:本番レベルイテレータパターン

イテレータを実際の本番シナリオに適用:データベースページネーション、ファイルストリーム処理、並行イテレーション。

// go-production-iterator/main.go
// 実行環境: Go 1.24+ / 追加依存なし
package main

import (
	"bufio"
	"fmt"
	"iter"
	"strings"
)

// ページネーションイテレータ
type Page[T any] struct {
	Items   []T
	PageNum int
	HasMore bool
}

func Paginate[T any](fetchPage func(pageNum int) (Page[T], error)) iter.Seq2[int, T] {
	return func(yield func(int, T) bool) {
		pageNum := 0
		for {
			page, err := fetchPage(pageNum)
			if err != nil { return }
			for _, item := range page.Items {
				if !yield(pageNum, item) { return }
			}
			if !page.HasMore { return }
			pageNum++
		}
	}
}

// ファイル行イテレータ
func LinesFromString(s string) iter.Seq[string] {
	return func(yield func(string) bool) {
		scanner := bufio.NewScanner(strings.NewReader(s))
		for scanner.Scan() {
			if !yield(scanner.Text()) { return }
		}
	}
}

// スライディングウィンドウイテレータ
func SlidingWindow[T any](size int, seq iter.Seq[T]) iter.Seq[[]T] {
	return func(yield func([]T) bool) {
		window := make([]T, 0, size)
		for v := range seq {
			window = append(window, v)
			if len(window) > size { window = window[1:] }
			if len(window) == size {
				snapshot := make([]T, size)
				copy(snapshot, window)
				if !yield(snapshot) { return }
			}
		}
	}
}

// ソート済みシーケンスの重複除去(追加メモリ不要)
func Deduplicate[T comparable](seq iter.Seq[T]) iter.Seq[T] {
	return func(yield func(T) bool) {
		var prev T
		first := true
		for v := range seq {
			if first || v != prev {
				first = false
				prev = v
				if !yield(v) { return }
			}
		}
	}
}

func main() {
	fmt.Println("=== ページネーションイテレータ ===")
	mockFetchPage := func(pageNum int) (Page[string], error) {
		allItems := [][]string{{"ユーザー1", "ユーザー2", "ユーザー3"}, {"ユーザー4", "ユーザー5"}, {"ユーザー6"}}
		if pageNum >= len(allItems) { return Page[string]{HasMore: false}, nil }
		return Page[string]{Items: allItems[pageNum], PageNum: pageNum, HasMore: pageNum < len(allItems)-1}, nil
	}
	for pageNum, user := range Paginate(mockFetchPage) {
		fmt.Printf("  ページ%d: %s\n", pageNum, user)
	}

	fmt.Println("\n=== スライディングウィンドウ ===")
	for window := range SlidingWindow(3, slicesToIter([]int{1, 2, 3, 4, 5, 6, 7})) {
		fmt.Print(window, " ")
	}
	fmt.Println()

	fmt.Print("重複除去: ")
	for v := range Deduplicate(slicesToIter([]int{1, 1, 2, 2, 3, 3, 3, 4})) {
		fmt.Print(v, " ")
	}
	fmt.Println()
}

func slicesToIter[T any](s []T) iter.Seq[T] {
	return func(yield func(T) bool) {
		for _, v := range s { if !yield(v) { return } }
	}
}

よくある落とし穴:5つの罠

罠1:イテレータ内で基盤コレクションを変更

// ❌ 間違い:走査中にスライスを変更
for i, v := range mySlice {
    mySlice = append(mySlice, v) // 危険!
}

// ✅ 正解:先にコピーしてから走査
copied := make([]int, len(mySlice))
copy(copied, mySlice)
for v := range slicesToIter(copied) { /* 安全 */ }

罠2:Pullイテレータでstopの呼び出し忘れ

// ❌ 間違い:stopが無視されている
next, _ := iter.Pull(mySeq)

// ✅ 正解:常にdefer stop
next, stop := iter.Pull(mySeq)
defer stop()

罠3:イテレータの再利用による予期しない動作

// ❌ 間違い:イテレータは消費される
seq := Range(5)
for v := range seq { fmt.Print(v) } // 0 1 2 3 4
for v := range seq { fmt.Print(v) } // 出力なし!

// ✅ 正解:毎回新しいイテレータを作成
for v := range Range(5) { fmt.Print(v) }
for v := range Range(5) { fmt.Print(v) }

罠4:再帰イテレータのスタックオーバーフロー

深い再帰ツリーはスタックオーバーフローを引き起こす可能性。明示的スタック(レベル順走査方式)を使用。

罠5:goroutineリーク

Bufferedイテレータでコンシューマが早期終了した場合、doneチャネルでプロデューサに終了を通知すること。

エラートラブルシューティング表

エラーメッセージ 原因 解決策
cannot range over xxx 型がiter.Seq/iter.Seq2ではない 関数シグネチャを確認
yield is not used イテレータ関数でyieldが呼ばれていない yield(v)の呼び出しを確保
cannot use seq as iter.Seq イテレータシグネチャの不一致 iter.Seq[T]vsiter.Seq2[K,V]を確認
panic: range over nil イテレータ関数がnil nilチェックを追加
goroutine leak Pullイテレータでstop未呼び出し defer stop()
stack overflow 再帰イテレータが深すぎる 明示的スタックイテレーションに変更
deadlock イテレータ内部チャネルのブロック contextキャンセルまたはタイムアウトを追加
unexpected address yieldはコピーを返す ポインタ*Tを使用
iterator consumed twice イテレータは1回しか消費できない 毎回新しいイテレータを作成
invalid memory address イテレータ内でクローズ済みリソースにアクセス リソースはイテレーション完了後にクローズ

高度な最適化:5つの本番レベルテクニック

テクニック1:イテレータとcontextの統合

func ContextAware[T any](ctx context.Context, seq iter.Seq[T]) iter.Seq[T] {
	return func(yield func(T) bool) {
		next, stop := iter.Pull(seq)
		defer stop()
		for {
			select {
			case <-ctx.Done():
				return
			default:
				v, ok := next()
				if !ok { return }
				if !yield(v) { return }
			}
		}
	}
}

テクニック2:並行イテレータ

goroutineとchannelを使用してParallelMapを実装し、イテレータ要素を並行処理。

テクニック3:イテレータパフォーマンスベンチマーク

Go benchmarkを使用してイテレータと従来のforループのパフォーマンス差を比較。

テクニック4:カスタムコレクションのiterインターフェース実装

OrderedMapなどのカスタムコレクションにAll()Keys()Values()イテレータメソッドを実装。

テクニック5:イテレータミドルウェアパターン

func WithMetrics[T any](name string, seq iter.Seq[T]) iter.Seq[T] {
	return func(yield func(T) bool) {
		count := 0
		start := time.Now()
		for v := range seq {
			count++
			if !yield(v) {
				log.Printf("[ITER:%s] interrupted after %d items", name, count)
				return
			}
		}
		log.Printf("[ITER:%s] completed %d items, elapsed: %v", name, count, time.Since(start))
	}
}

Goイテレータ vs 他言語比較

次元 Go 1.24 iter Python Generator Rust Iterator Java Stream
func(yield func(V) bool) yield v trait Iterator Stream<T>
ジェネリクス ✅ 完全ジェネリクス ❌ 動的型付け ✅ 完全ジェネリクス ✅ 完全ジェネリクス
遅延評価 ✅ 天然の遅延 ✅ 天然の遅延 ✅ 天然の遅延 ✅ Pull/Push選択可能
早期終了 ✅ yieldがfalseを返す ✅ break ✅ take/scan ⚠️ 短絡操作が必要
合成性 ✅ 関数合成 ✅ ジェネレータ合成 ✅ アダプタ合成 ✅ ストリーム操作
並行安全性 ❌ 非並行安全 ❌ GIL制限 ❌ 非並行安全 ✅ パラレルストリーム
パフォーマンス 低(関数呼び出し) 高(インタプリタ実行) ゼロコスト抽象化 中(ボクシング/アンボクシング)
学習曲線 中高
エコシステム成熟度 新(1.23導入) 成熟 成熟 成熟

まとめ

Go 1.24のrange over funcイテレータはGo言語の表現力を大きく向上させます:

  • 基礎パターンiter.Seq[T]iter.Seq2[K,V]の2つのシグネチャを理解、yieldがfalseを返す早期終了メカニズムをマスター
  • ジェネリックイテレータ:Filter/Map/Reduce/Chunkなどのユーティリティ関数でデータ処理をパイプラインのようにエレガントに
  • ツリー/グラフ探索:再帰探索をイテレータにカプセル化、合成可能、中断可能、再利用可能
  • イテレータパイプライン:Concat/Interleave/TakeWhile/DropWhileでデータフローを合成
  • 本番パターン:ページネーションイテレータ、ファイルストリーム、スライディングウィンドウ、context対応キャンセル

重要原則:イテレータは消費される、非並行安全、天然の遅延評価。この3点を理解すれば90%の罠を回避できます。

オンラインツールおすすめ

  • /ja/json/format - JSONフォーマッター、イテレータが返すJSONデータの処理
  • /ja/dev/curl-to-code - cURL→コード変換、Go HTTPイテレータの迅速生成
  • /ja/encode/hash - ハッシュ計算、イテレータ重複除去と検証
  • /ja/text/diff - テキスト差分、イテレータバージョン変更の比較

ブラウザローカルツールを無料で試す →

#Go 1.24#迭代器#range over func#泛型迭代器#Go新特性#2026#编程语言