Go 1.24 Iterator Advanced: range over func Deep Practice 2026

编程语言

Go 1.24 Iterator Advanced: range over func Deep Practice

Go 1.22 introduced range over int, Go 1.23 introduced range over func — Go finally has "first-class" iterators. But many Gophers are still stuck at for i, v := range slice, with their understanding of range over func limited to the standard library's slices and maps packages.

By Go 1.24, the iterator ecosystem has matured: generic iterators, iterator composition, lazy evaluation pipelines... these patterns can make your Go code more elegant, more efficient, and more Go-idiomatic. This article walks through 5 core patterns to help you fully master Go iterators.

Core Concepts at a Glance

Concept Description Signature
Iterator Function Function type that can be ranged over func(yield func(V) bool)
Indexed Iterator Returns both index and value func(yield func(int, V) bool)
Pull Iterator Manually pull next value func() (V, bool)
Push Iterator Push values to yield callback func(yield func(V) bool)
Iterator Composition Chain/merge multiple iterators func(...Iter) Iter
Lazy Evaluation Deferred computation until consumption Iterators are naturally lazy

5 Major Pain Points of Go Iterators

  1. Verbose custom collection traversal: Trees, graphs, linked lists require hand-written traversal callbacks
  2. Missing pipeline-style data processing: Can't chain filter/map like Python generators
  3. Complex generic iterator types: func(yield func(V) bool) signature confuses beginners
  4. Iterator-goroutine interaction: Correct usage patterns for concurrent iterators are unclear
  5. Pull vs Push confusion: When to use which iterator mode is ambiguous

Pattern 1: range over func Basics

The three iterator function signatures introduced in Go 1.23 are the foundation for understanding everything.

// go-iterator-basics/main.go
// Environment: Go 1.24+ / No extra dependencies
package main

import (
	"fmt"
	"iter"
)

// Range generates an integer sequence iterator
func Range(n int) iter.Seq[int] {
	return func(yield func(int) bool) {
		for i := range n {
			if !yield(i) {
				return
			}
		}
	}
}

// RangeWithStep generates an integer sequence with step
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 adds indices to any slice
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 only the first n elements
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 converts a Push iterator to a Pull iterator
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("=== Basic Iterator ===")
	for i := range Range(5) {
		fmt.Print(i, " ") // 0 1 2 3 4
	}
	fmt.Println()

	fmt.Println("=== With Step ===")
	for i := range RangeWithStep(0, 20, 5) {
		fmt.Print(i, " ") // 0 5 10 15
	}
	fmt.Println()

	fmt.Println("=== With Index ===")
	fruits := []string{"Apple", "Banana", "Cherry"}
	for i, fruit := range Enumerate(fruits) {
		fmt.Printf("%d: %s  ", i, fruit)
	}
	fmt.Println()

	fmt.Println("=== Early Exit ===")
	for v := range Take(3, Range(100)) {
		fmt.Print(v, " ") // 0 1 2
	}
	fmt.Println()

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

Pattern 2: Generic Iterators

Generics make iterators true "first-class citizens" — a single Filter function can filter sequences of any type.

// go-generic-iterator/main.go
// Environment: Go 1.24+ / No extra dependencies
package main

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

// Filter elements in a sequence
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 transforms each element in a sequence
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 transforms and flattens each element
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 a sequence to a single value
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 a sequence into fixed-size groups
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 removes duplicate elements
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})

	// Chain: filter evens → square → take first 3
	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("Chain: ")
	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:", sum) // 15

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

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

	// FlatMap
	sentences := slicesToIter([]string{"hello world", "go is great"})
	words := FlatMap(sentences, func(s string) iter.Seq[string] {
		return slicesToIter(strings.Split(s, " "))
	})
	fmt.Print("FlatMap: ")
	for w := range words {
		fmt.Print(w, " ") // hello world go is great
	}
	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
			}
		}
	}
}

Pattern 3: Tree/Graph Traversal Iterators

The most powerful application of iterators — turning recursive traversal into composable pipelines.

// go-tree-iterator/main.go
// Environment: Go 1.24+ / No extra dependencies
package main

import (
	"fmt"
	"iter"
)

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

// InOrder traversal iterator (Left-Root-Right)
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 traversal iterator (Root-Left-Right)
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 traversal iterator (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 definition
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 depth-first traversal iterator
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 breadth-first traversal iterator
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("InOrder: ")
	for v := range root.InOrder() { fmt.Print(v, " ") } // 1 2 3 4 5 6 7
	fmt.Println()

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

	fmt.Print("LevelOrder: ")
	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, " ") } // A B D E C
	fmt.Println()

	fmt.Print("BFS: ")
	for v := range g.BFS("A") { fmt.Print(v, " ") } // A B C D E
	fmt.Println()
}

Pattern 4: Iterator Composition and Pipelines

The most elegant use of iterators — composing data processing flows like Unix pipes.

// go-iterator-pipeline/main.go
// Environment: Go 1.24+ / No extra dependencies
package main

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

// Concat concatenates multiple iterators
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 }
			}
		}
	}
}

// Interleave alternates elements from multiple iterators
func Interleave[T any](seqs ...iter.Seq[T]) iter.Seq[T] {
	return func(yield func(T) bool) {
		pulls := make([]func() (T, bool), len(seqs))
		stops := make([]func(), len(seqs))
		for i, seq := range seqs {
			pulls[i], stops[i] = iter.Pull(seq)
		}
		defer func() { for _, stop := range stops { stop() } }()

		active := len(seqs)
		for active > 0 {
			for i, pull := range pulls {
				v, ok := pull()
				if !ok { pulls[i] = nil; active--; continue }
				if !yield(v) { return }
			}
		}
	}
}

// TakeWhile takes values while predicate is 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 skips values while predicate is 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 }
		}
	}
}

// Log processing pipeline
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("Concat: ")
	for v := range Concat(slicesToIter([]int{1, 2, 3}), slicesToIter([]int{4, 5, 6})) {
		fmt.Print(v, " ") // 1 2 3 4 5 6
	}
	fmt.Println()

	fmt.Print("Interleave: ")
	for v := range Interleave(slicesToIter([]string{"A", "B", "C"}), slicesToIter([]string{"1", "2", "3"})) {
		fmt.Print(v, " ") // A 1 B 2 C 3
	}
	fmt.Println()

	// Log pipeline
	rawLogs := slicesToIter([]string{
		"2026-01-01 ERROR Database connection failed",
		"2026-01-01 INFO Service started",
		"2026-01-01 ERROR Cache timeout",
		"2026-01-01 WARN High memory usage",
	})

	fmt.Println("\n=== Log Pipeline: ERROR messages only ===")
	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++
		}
	}
}

Pattern 5: Production-Grade Iterator Patterns

Applying iterators to real production scenarios: database pagination, file stream processing, concurrent iteration.

// go-production-iterator/main.go
// Environment: Go 1.24+ / No extra dependencies
package main

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

// Pagination iterator
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++
		}
	}
}

// File line iterator
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 }
		}
	}
}

// Sliding window iterator
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 }
			}
		}
	}
}

// Deduplicate sorted sequence (no extra memory)
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("=== Pagination Iterator ===")
	mockFetchPage := func(pageNum int) (Page[string], error) {
		allItems := [][]string{{"User1", "User2", "User3"}, {"User4", "User5"}, {"User6"}}
		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("  Page %d: %s\n", pageNum, user)
	}

	fmt.Println("\n=== Sliding Window ===")
	for window := range SlidingWindow(3, slicesToIter([]int{1, 2, 3, 4, 5, 6, 7})) {
		fmt.Print(window, " ") // [1 2 3] [2 3 4] [3 4 5] [4 5 6] [5 6 7]
	}
	fmt.Println()

	fmt.Print("Deduplicate: ")
	for v := range Deduplicate(slicesToIter([]int{1, 1, 2, 2, 3, 3, 3, 4})) {
		fmt.Print(v, " ") // 1 2 3 4
	}
	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 } }
	}
}

Pitfall Guide: 5 Common Traps

Trap 1: Modifying Underlying Collection During Iteration

// ❌ Wrong: Modifying slice during iteration
for i, v := range mySlice {
    mySlice = append(mySlice, v) // Dangerous!
}

// ✅ Right: Copy first, then iterate
copied := make([]int, len(mySlice))
copy(copied, mySlice)
for v := range slicesToIter(copied) { /* safe */ }

Trap 2: Forgetting to Call stop on Pull Iterators

// ❌ Wrong: stop is ignored
next, _ := iter.Pull(mySeq)

// ✅ Right: Always defer stop
next, stop := iter.Pull(mySeq)
defer stop()

Trap 3: Reusing Iterators Causes Unexpected Behavior

// ❌ Wrong: Iterators are consumable
seq := Range(5)
for v := range seq { fmt.Print(v) } // 0 1 2 3 4
for v := range seq { fmt.Print(v) } // No output!

// ✅ Right: Create new iterator each time
for v := range Range(5) { fmt.Print(v) }
for v := range Range(5) { fmt.Print(v) }

Trap 4: Recursive Iterator Stack Overflow

Deep recursive trees may cause stack overflow. Use explicit stack (level-order style) instead.

Trap 5: Goroutine Leaks

When a consumer exits early from a Buffered iterator, ensure the done channel can notify the producer to stop.

Error Troubleshooting Table

Error Message Cause Solution
cannot range over xxx Type is not iter.Seq/iter.Seq2 Verify function signature is func(yield func(V) bool)
yield is not used yield not called in iterator function Ensure yield(v) is called in loop
cannot use seq as iter.Seq Iterator signature mismatch Check iter.Seq[T] vs iter.Seq2[K,V]
panic: range over nil Iterator function is nil Add nil check, return empty iterator
goroutine leak Pull iterator stop not called defer stop()
stack overflow Recursive iterator too deep Use explicit stack iteration
deadlock Iterator internal channel blocked Add context cancellation or timeout
unexpected address yield returns a copy Go value semantics; use *T for pointers
iterator consumed twice Iterator can only be consumed once Create new iterator each time
invalid memory address Accessing closed resource in iterator Ensure resources close after iteration completes

Advanced Optimization: 5 Production-Grade Tips

Tip 1: Iterator + Context Integration

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 }
			}
		}
	}
}

Tip 2: Parallel Iterators

Implement ParallelMap using goroutines and channels for concurrent element processing.

Tip 3: Iterator Performance Benchmarks

Use Go benchmarks to compare iterator vs traditional for-loop performance.

Tip 4: Custom Collections Implementing iter Interface

Implement All(), Keys(), Values() iterator methods for custom collections like OrderedMap.

Tip 5: Iterator Middleware Pattern

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 Iterators vs Other Languages

Dimension Go 1.24 iter Python Generator Rust Iterator Java Stream
Type func(yield func(V) bool) yield v trait Iterator Stream<T>
Generics ✅ Full generics ❌ Dynamic typing ✅ Full generics ✅ Full generics
Lazy Evaluation ✅ Naturally lazy ✅ Naturally lazy ✅ Naturally lazy ✅ Pull/push optional
Early Exit ✅ yield returns false ✅ break ✅ take/scan ⚠️ Needs short-circuit ops
Composability ✅ Function composition ✅ Generator composition ✅ Adapter composition ✅ Stream operations
Concurrency Safe ❌ Not safe ❌ GIL limited ❌ Not safe ✅ Parallel streams
Performance Overhead Low (function call) High (interpreted) Zero-cost abstraction Medium (boxing/unboxing)
Learning Curve Medium Low Medium-High Medium
Ecosystem Maturity New (1.23) Mature Mature Mature

Conclusion

Go 1.24's range over func iterators are a significant boost to Go's expressiveness:

  • Basics: Understand iter.Seq[T] and iter.Seq2[K,V] signatures, master yield-returning-false early exit
  • Generic iterators: Filter/Map/Reduce/Chunk make data processing elegant as pipelines
  • Tree/Graph traversal: Encapsulate recursive traversal as composable, interruptible, reusable iterators
  • Iterator pipelines: Concat/Interleave/TakeWhile/DropWhile for data flow composition
  • Production patterns: Pagination iterators, file streams, sliding windows, context-aware cancellation

Key principles: iterators are consumable, not concurrency-safe, and naturally lazy. Understanding these three points helps you avoid 90% of pitfalls.

Try these browser-local tools — no sign-up required →

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