Go iter 包详解
概述
iter 包是 Go 1.23 引入的新包,提供了用于迭代器的基础类型和函数。迭代器是 Go 1.23 的重大更新之一,允许使用 for range 循环自定义的迭代逻辑。该包定义了 Seq 和 Seq2 类型,以及相关的辅助函数,为集合遍历提供了统一的方式。
包导入
import "iter"
基本使用
1. 简单的迭代器
package main
import (
"fmt"
"iter"
)
func main() {
// 创建一个简单的序列
for v := range iter.Seq[int](func(yield func(int) bool) {
for i := 0; i < 5; i++ {
if !yield(i) {
return
}
}
}) {
fmt.Println(v)
}
// 输出:0 1 2 3 4
}
2. 使用 Seq2 迭代键值对
package main
import (
"fmt"
"iter"
)
func main() {
// 创建键值对序列
for k, v := range iter.Seq2[int, string](func(yield func(int, string) bool) {
for i := 0; i < 3; i++ {
if !yield(i, fmt.Sprintf("item%d", i)) {
return
}
}
}) {
fmt.Printf("%d: %s\n", k, v)
}
// 输出:
// 0: item0
// 1: item1
// 2: item2
}
3. 自定义迭代器函数
package main
import (
"fmt"
"iter"
)
// 创建斐波那契数列迭代器
func Fibonacci(n int) iter.Seq[int] {
return func(yield func(int) bool) {
a, b := 0, 1
for i := 0; i < n; i++ {
if !yield(a) {
return
}
a, b = b, a+b
}
}
}
func main() {
for v := range Fibonacci(10) {
fmt.Print(v, " ")
}
// 输出:0 1 1 2 3 5 8 13 21 34
}
一、核心类型
Seq
定义:
type Seq[V any] func(yield func(V) bool) bool
说明:
- 功能:单值迭代器类型
- 类型参数:
V- 迭代值的类型 - 参数:
yield- 用于产生值的函数,返回 false 表示停止迭代 - 返回值:bool - 表示迭代是否完成
- 用途:用于
for range循环的单值迭代
示例:
package main
import (
"fmt"
"iter"
)
// 示例 1:创建数字序列
func Range(start, end int) iter.Seq[int] {
return func(yield func(int) bool) {
for i := start; i < end; i++ {
if !yield(i) {
return
}
}
}
}
func main() {
// 使用迭代器
for n := range Range(1, 6) {
fmt.Println(n)
}
// 输出:1 2 3 4 5
// 示例 2:提前退出
for n := range Range(1, 100) {
if n > 3 {
break // 自动停止迭代
}
fmt.Println(n)
}
// 输出:1 2 3
}
Seq2
定义:
type Seq2[K, V any] func(yield func(K, V) bool) bool
说明:
- 功能:双值迭代器类型(键值对)
- 类型参数:
K- 键的类型V- 值的类型
- 参数:
yield- 用于产生键值对的函数 - 返回值:bool - 表示迭代是否完成
- 用途:用于
for range循环的键值对迭代
示例:
package main
import (
"fmt"
"iter"
)
// 示例 1:创建键值对序列
func Enumerate[T any](slice []T) iter.Seq2[int, T] {
return func(yield func(int, T) bool) {
for i, v := range slice {
if !yield(i, v) {
return
}
}
}
}
// 示例 2:Map 迭代
func MapItems[K comparable, V any](m map[K]V) iter.Seq2[K, V] {
return func(yield func(K, V) bool) {
for k, v := range m {
if !yield(k, v) {
return
}
}
}
}
func main() {
// 使用枚举迭代器
slice := []string{"a", "b", "c"}
for i, v := range Enumerate(slice) {
fmt.Printf("%d: %s\n", i, v)
}
// 输出:
// 0: a
// 1: b
// 2: c
// 使用 Map 迭代器
m := map[string]int{
"one": 1,
"two": 2,
"three": 3,
}
for k, v := range MapItems(m) {
fmt.Printf("%s: %d\n", k, v)
}
}
二、辅助函数
All
定义:
func All[V any](seq Seq[V]) func() (V, bool)
说明:
- 功能:将迭代器转换为传统的迭代函数
- 类型参数:
V- 值的类型 - 参数:
seq- 迭代器序列 - 返回值:
func() (V, bool)- 每次调用返回下一个值和是否存在 - 用途:与不支持
for range的代码兼容
示例:
package main
import (
"fmt"
"iter"
)
func Range(start, end int) iter.Seq[int] {
return func(yield func(int) bool) {
for i := start; i < end; i++ {
if !yield(i) {
return
}
}
}
}
func main() {
// 使用 All 转换为传统迭代
next := iter.All(Range(1, 6))
for {
v, ok := next()
if !ok {
break
}
fmt.Println(v)
}
// 输出:1 2 3 4 5
// 手动控制迭代
next2 := iter.All(Range(1, 10))
fmt.Println(next2()) // 1, true
fmt.Println(next2()) // 2, true
fmt.Println(next2()) // 3, true
}
All2
定义:
func All2[K, V any](seq Seq2[K, V]) func() (K, V, bool)
说明:
- 功能:将双值迭代器转换为传统的迭代函数
- 类型参数:
K- 键的类型V- 值的类型
- 参数:
seq- 双值迭代器序列 - 返回值:
func() (K, V, bool)- 每次调用返回下一个键、值和是否存在 - 用途:与不支持
for range的代码兼容
示例:
package main
import (
"fmt"
"iter"
)
func Enumerate[T any](slice []T) iter.Seq2[int, T] {
return func(yield func(int, T) bool) {
for i, v := range slice {
if !yield(i, v) {
return
}
}
}
}
func main() {
slice := []string{"a", "b", "c"}
// 使用 All2 转换
next := iter.All2(Enumerate(slice))
for {
i, v, ok := next()
if !ok {
break
}
fmt.Printf("%d: %s\n", i, v)
}
// 输出:
// 0: a
// 1: b
// 2: c
// 手动控制
next2 := iter.All2(Enumerate(slice))
i, v, ok := next2()
fmt.Printf("%d: %s, ok=%v\n", i, v, ok) // 0: a, ok=true
i, v, ok = next2()
fmt.Printf("%d: %s, ok=%v\n", i, v, ok) // 1: b, ok=true
}
Pull
定义:
func Pull[V any](seq Seq[V]) func(func() V, func() bool)
说明:
- 功能:将迭代器转换为 pull 风格的迭代器
- 类型参数:
V- 值的类型 - 参数:
seq- 迭代器序列 - 返回值:接收两个函数的函数
- 用途:更灵活地控制迭代过程
示例:
package main
import (
"fmt"
"iter"
)
func Range(start, end int) iter.Seq[int] {
return func(yield func(int) bool) {
for i := start; i < end; i++ {
if !yield(i) {
return
}
}
}
}
func main() {
// 使用 Pull 创建 pull 风格迭代器
iter.Pull(Range(1, 6))(
func() V {
// 获取值的回调
return // 实际使用中会返回值
},
func() bool {
// 检查是否还有值的回调
return true
},
)
}
Pull2
定义:
func Pull2[K, V any](seq Seq2[K, V]) func(func() (K, V), func() bool)
说明:
- 功能:将双值迭代器转换为 pull 风格的迭代器
- 类型参数:
K- 键的类型V- 值的类型
- 参数:
seq- 双值迭代器序列 - 返回值:接收两个函数的函数
- 用途:更灵活地控制键值对迭代
三、典型示例
示例 1:链表迭代器
package main
import (
"fmt"
"iter"
)
// Node 链表节点
type Node[T any] struct {
Value T
Next *Node[T]
}
// List 链表
type List[T any] struct {
Head *Node[T]
}
// All 返回迭代器
func (l *List[T]) All() iter.Seq[T] {
return func(yield func(T) bool) {
current := l.Head
for current != nil {
if !yield(current.Value) {
return
}
current = current.Next
}
}
}
// AllWithIndex 返回带索引的迭代器
func (l *List[T]) AllWithIndex() iter.Seq2[int, T] {
return func(yield func(int, T) bool) {
current := l.Head
index := 0
for current != nil {
if !yield(index, current.Value) {
return
}
current = current.Next
index++
}
}
}
func main() {
// 创建链表
list := &List[int]{}
list.Head = &Node[int]{Value: 1}
list.Head.Next = &Node[int]{Value: 2}
list.Head.Next.Next = &Node[int]{Value: 3}
// 遍历链表
fmt.Print("链表:")
for v := range list.All() {
fmt.Print(v, " ")
}
fmt.Println()
// 输出:链表:1 2 3
// 带索引遍历
fmt.Println("带索引:")
for i, v := range list.AllWithIndex() {
fmt.Printf("[%d]=%d ", i, v)
}
fmt.Println()
// 输出:带索引:[0]=1 [1]=2 [2]=3
}
示例 2:树形结构迭代
package main
import (
"fmt"
"iter"
)
// TreeNode 树节点
type TreeNode struct {
Value int
Children []*TreeNode
}
// DFS 深度优先遍历
func (n *TreeNode) DFS() iter.Seq[int] {
return func(yield func(int) bool) {
n.dfsRecursive(yield)
}
}
func (n *TreeNode) dfsRecursive(yield func(int) bool) bool {
if n == nil {
return true
}
if !yield(n.Value) {
return false
}
for _, child := range n.Children {
if !child.dfsRecursive(yield) {
return false
}
}
return true
}
// BFS 广度优先遍历
func (n *TreeNode) BFS() iter.Seq[int] {
return func(yield func(int) bool) {
if n == nil {
return
}
queue := []*TreeNode{n}
for len(queue) > 0 {
node := queue[0]
queue = queue[1:]
if !yield(node.Value) {
return
}
queue = append(queue, node.Children...)
}
}
}
func main() {
// 创建树
root := &TreeNode{Value: 1}
node2 := &TreeNode{Value: 2}
node3 := &TreeNode{Value: 3}
node4 := &TreeNode{Value: 4}
node5 := &TreeNode{Value: 5}
root.Children = []*TreeNode{node2, node3}
node2.Children = []*TreeNode{node4, node5}
// DFS 遍历
fmt.Print("DFS: ")
for v := range root.DFS() {
fmt.Print(v, " ")
}
fmt.Println()
// 输出:DFS: 1 2 4 5 3
// BFS 遍历
fmt.Print("BFS: ")
for v := range root.BFS() {
fmt.Print(v, " ")
}
fmt.Println()
// 输出:BFS: 1 2 3 4 5
}
示例 3:通道迭代器
package main
import (
"fmt"
"iter"
)
// FromChannel 从通道创建迭代器
func FromChannel[T any](ch <-chan T) iter.Seq[T] {
return func(yield func(T) bool) {
for v := range ch {
if !yield(v) {
return
}
}
}
}
// ToChannel 将迭代器转换为通道
func ToChannel[T any](seq iter.Seq[T]) <-chan T {
ch := make(chan T)
go func() {
defer close(ch)
for v := range seq {
ch <- v
}
}()
return ch
}
func main() {
// 创建通道
ch := make(chan int)
go func() {
for i := 0; i < 5; i++ {
ch <- i
}
close(ch)
}()
// 使用迭代器遍历通道
fmt.Print("通道迭代:")
for v := range FromChannel(ch) {
fmt.Print(v, " ")
}
fmt.Println()
// 将迭代器转换为通道
seq := func(yield func(int) bool) {
for i := 0; i < 5; i++ {
if !yield(i) {
return
}
}
}
ch2 := ToChannel(seq)
fmt.Print("迭代器转通道:")
for v := range ch2 {
fmt.Print(v, " ")
}
fmt.Println()
}
示例 4:过滤和转换
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, U any](seq iter.Seq[T], transform func(T) U) iter.Seq[U] {
return func(yield func(U) bool) {
for v := range seq {
if !yield(transform(v)) {
return
}
}
}
}
// Take 取前 N 个元素
func Take[T any](seq iter.Seq[T], n int) iter.Seq[T] {
return func(yield func(T) bool) {
count := 0
for v := range seq {
if count >= n {
return
}
if !yield(v) {
return
}
count++
}
}
}
func main() {
// 创建序列
numbers := func(yield func(int) bool) {
for i := 1; i <= 10; i++ {
if !yield(i) {
return
}
}
}
// 过滤偶数
fmt.Print("偶数:")
for n := range Filter(numbers, func(n int) bool {
return n%2 == 0
}) {
fmt.Print(n, " ")
}
fmt.Println()
// 输出:偶数:2 4 6 8 10
// 转换为平方
fmt.Print("平方:")
for n := range Map(numbers, func(n int) int {
return n * n
}) {
fmt.Print(n, " ")
}
fmt.Println()
// 输出:平方:1 4 9 16 25 36 49 64 81 100
// 取前 5 个
fmt.Print("前 5 个:")
for n := range Take(numbers, 5) {
fmt.Print(n, " ")
}
fmt.Println()
// 输出:前 5 个:1 2 3 4 5
// 链式操作
fmt.Print("前 5 个偶数的平方:")
for n := range Take(Map(Filter(numbers, func(n int) bool {
return n%2 == 0
}), func(n int) int {
return n * n
}), 5) {
fmt.Print(n, " ")
}
fmt.Println()
// 输出:前 5 个偶数的平方:4 16 36 64 100
}
示例 5:字符串处理
package main
import (
"fmt"
"iter"
"strings"
)
// Lines 按行迭代字符串
func Lines(s string) iter.Seq[string] {
return func(yield func(string) bool) {
for _, line := range strings.Split(s, "\n") {
if !yield(line) {
return
}
}
}
}
// Words 按单词迭代字符串
func Words(s string) iter.Seq[string] {
return func(yield func(string) bool) {
for _, word := range strings.Fields(s) {
if !yield(word) {
return
}
}
}
}
// Runes 按字符迭代字符串
func Runes(s string) iter.Seq[rune] {
return func(yield func(rune) bool) {
for _, r := range s {
if !yield(r) {
return
}
}
}
}
func main() {
text := `Hello World
This is Go
iter package`
// 按行迭代
fmt.Println("按行:")
for line := range Lines(text) {
fmt.Printf(" %s\n", line)
}
// 按单词迭代
fmt.Println("\n按单词:")
for word := range Words(text) {
fmt.Printf(" %s\n", word)
}
// 按字符迭代
fmt.Print("\n按字符:")
count := 0
for r := range Runes("Hello") {
if count >= 5 {
break
}
fmt.Printf("%c ", r)
count++
}
fmt.Println()
}
四、最佳实践
1. 提前退出
// 迭代器会自动处理提前退出
func Find[T any](seq iter.Seq[T], predicate func(T) bool) (T, bool) {
var zero T
for v := range seq {
if predicate(v) {
return v, true
}
}
return zero, false
}
// 使用
result, found := Find(numbers, func(n int) bool {
return n > 5
})
2. 惰性求值
// 迭代器是惰性求值的,只在需要时计算
func LargeNumbers() iter.Seq[int] {
return func(yield func(int) bool) {
fmt.Println("开始生成")
for i := 0; ; i++ {
fmt.Printf("生成 %d\n", i)
if !yield(i) {
fmt.Println("提前退出")
return
}
}
}
}
// 只生成前 3 个
for n := range Take(LargeNumbers(), 3) {
fmt.Println(n)
}
3. 组合操作
// 链式组合多个操作
func ProcessData(data []int) {
seq := Slice(data)
// 过滤 -> 转换 -> 限制
for v := range Take(
Map(
Filter(seq, func(n int) bool {
return n%2 == 0
}),
func(n int) int {
return n * n
},
),
10,
) {
fmt.Println(v)
}
}
4. 错误处理
// 在迭代器中处理错误
func SafeReadLines(filename string) iter.Seq[string] {
return func(yield func(string) bool) {
file, err := os.Open(filename)
if err != nil {
return
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
if !yield(scanner.Text()) {
return
}
}
}
}
五、与其他包配合
1. 与切片配合
// Slice 将切片转换为迭代器
func Slice[T any](s []T) iter.Seq[T] {
return func(yield func(T) bool) {
for _, v := range s {
if !yield(v) {
return
}
}
}
}
// Slice2 将切片转换为键值对迭代器
func Slice2[T any](s []T) iter.Seq2[int, T] {
return func(yield func(int, T) bool) {
for i, v := range s {
if !yield(i, v) {
return
}
}
}
}
2. 与 Map 配合
// Keys 迭代 Map 的键
func Keys[K comparable, V any](m map[K]V) iter.Seq[K] {
return func(yield func(K) bool) {
for k := range m {
if !yield(k) {
return
}
}
}
}
// Values 迭代 Map 的值
func Values[K comparable, V any](m map[K]V) iter.Seq[V] {
return func(yield func(V) bool) {
for _, v := range m {
if !yield(v) {
return
}
}
}
}
3. 与通道配合
// 见示例 3:通道迭代器
六、快速参考
类型总览
| 类型名 | 定义 | 描述 |
|---|---|---|
Seq[V] | func(yield func(V) bool) bool | 单值迭代器 |
Seq2[K,V] | func(yield func(K,V) bool) bool | 双值迭代器 |
函数总览
| 函数名 | 参数 | 返回值 | 描述 |
|---|---|---|---|
All | seq Seq[V] | func() (V, bool) | 转换为单值迭代函数 |
All2 | seq Seq2[K,V] | func() (K, V, bool) | 转换为双值迭代函数 |
Pull | seq Seq[V] | func(...) | 转换为 pull 风格 |
Pull2 | seq Seq2[K,V] | func(...) | 转换为 pull 风格 |
常见迭代器模式
| 模式 | 实现方式 |
|---|---|
| 序列生成 | for 循环 + yield |
| 过滤 | 条件判断 + yield |
| 转换 | 转换函数 + yield |
| 限制 | 计数器 + return |
| 树遍历 | 递归 + yield |
性能特点
| 特性 | 说明 |
|---|---|
| 惰性求值 | 只在需要时计算 |
| 零拷贝 | 不创建中间切片 |
| 自动停止 | 支持 break 提前退出 |
| 内存高效 | O(1) 额外空间 |
七、注意事项
1. yield 的使用
// 正确:检查 yield 返回值
func Correct() iter.Seq[int] {
return func(yield func(int) bool) {
for i := 0; i < 10; i++ {
if !yield(i) {
return // ✓ 提前退出
}
}
}
}
// 错误:忽略 yield 返回值
func Incorrect() iter.Seq[int] {
return func(yield func(int) bool) {
for i := 0; i < 10; i++ {
yield(i) // ✗ 不检查返回值
}
}
}
2. 闭包变量捕获
// 注意:避免闭包捕获循环变量
func BadExample() iter.Seq[func() int] {
return func(yield func(func() int) bool) {
for i := 0; i < 3; i++ {
// ✗ 错误:所有函数都捕获同一个 i
if !yield(func() int { return i }) {
return
}
}
}
}
func GoodExample() iter.Seq[func() int] {
return func(yield func(func() int) bool) {
for i := 0; i < 3; i++ {
// ✓ 正确:创建新变量
v := i
if !yield(func() int { return v }) {
return
}
}
}
}
3. 并发安全
// 迭代器本身不是并发安全的
// 需要在外部同步
func ConcurrentSafe(ch <-chan int) iter.Seq[int] {
return func(yield func(int) bool) {
// 使用通道保证并发安全
for v := range ch {
if !yield(v) {
return
}
}
}
}
4. 资源管理
// 确保资源正确释放
func WithResource() iter.Seq[string] {
return func(yield func(string) bool) {
file, err := os.Open("data.txt")
if err != nil {
return
}
defer file.Close() // ✓ 使用 defer 保证释放
scanner := bufio.NewScanner(file)
for scanner.Scan() {
if !yield(scanner.Text()) {
return
}
}
}
}
八、完整示例:数据处理管道
package main
import (
"fmt"
"iter"
"strconv"
"strings"
)
// 数据处理管道示例
// ParseInts 解析字符串为整数
func ParseInts(s string) iter.Seq[int] {
return func(yield func(int) bool) {
for _, part := range strings.Fields(s) {
if n, err := strconv.Atoi(part); err == nil {
if !yield(n) {
return
}
}
}
}
}
// Filter 过滤
func Filter(seq iter.Seq[int], predicate func(int) bool) iter.Seq[int] {
return func(yield func(int) bool) {
for v := range seq {
if predicate(v) {
if !yield(v) {
return
}
}
}
}
}
// Map 转换
func Map(seq iter.Seq[int], transform func(int) int) iter.Seq[int] {
return func(yield func(int) bool) {
for v := range seq {
if !yield(transform(v)) {
return
}
}
}
}
// Sum 求和
func Sum(seq iter.Seq[int]) int {
sum := 0
for v := range seq {
sum += v
}
return sum
}
// Count 计数
func Count(seq iter.Seq[int]) int {
count := 0
for range seq {
count++
}
return count
}
func main() {
data := "1 2 3 4 5 6 7 8 9 10"
// 构建数据处理管道
// 1. 解析字符串
// 2. 过滤偶数
// 3. 计算平方
// 4. 求和
result := Sum(
Map(
Filter(
ParseInts(data),
func(n int) bool { return n%2 == 0 },
),
func(n int) int { return n * n },
),
)
fmt.Printf("偶数平方和:%d\n", result)
// 输出:偶数平方和:220 (4+16+36+64+100)
// 统计偶数个数
count := Count(
Filter(
ParseInts(data),
func(n int) bool { return n%2 == 0 },
),
)
fmt.Printf("偶数个数:%d\n", count)
// 输出:偶数个数:5
}
最后更新: 2026-04-04
Go 版本: 1.23+
包文档: https://pkg.go.dev/iter