iter.Seq[T]是Go 1.23引入的唯一可直接for range的函数类型,签名必须为func(yield func(T) bool) error;其他类型或错误签名均报编译错误,且yield返回false时须立即退出。
iter.Seq 是唯一能直接用 for range 的迭代器类型
go 1.23 正式将 iter.seq[t] 纳入标准库,它不是接口,也不是结构体,而是一个函数类型:func(yield func(t) bool) error。只有符合这个签名的值,才能被 for range 直接消费。其他任何自定义类型(比如带 next() 方法的 struct)或错误签名的函数(如返回 bool 而非 error),都会触发 cannot range over … 编译错误。
常见错误包括:
- 写成
func() iter.Seq[T]—— 多套了一层函数,for range拿到的是func(),不是iter.Seq[T] - 把
yield参数写成func(T) bool但返回值写成bool,必须是error - 在 Go golang.org/x/exp/iter,又没开
GOEXPERIMENT=rangefunc,也会报同样错误
普通切片、map 就别包装了,直接 for range
标准集合([]T、map[K]V、string、chan T)原生支持 for range,性能最优、语义最清晰。强行用 iter.Seq 包一层,只会增加闭包开销、掩盖数据来源,还可能引入并发风险(比如 yield 被多个 goroutine 同时调用,而底层 slice 是共享的)。
真正该用 iter.Seq 的场景只有三个:
- 封装外部数据源:数据库游标、文件逐行读取、HTTP 流式响应
- 实现延迟计算:比如无限数列、按需生成的斐波那契序列
- 统一多种数据源接口:让
[]T、chan T、*sql.Rows都能走同一套处理逻辑
yield 返回 false 必须立刻 break,否则会越界或 panic
yield 函数的返回值控制遍历节奏:返回 true 表示继续,false 表示消费者已终止(例如 break 或 return)。此时你的迭代器函数必须立即退出循环,不能再调用 yield,也不能继续访问底层数据。
典型错误写法:
type Iterator struct { items []T; idx int }
-
filepath.Walk:接受func(path string, info fs.FileInfo, err error) error -
database/sql.Rows.Scan:配合Rows.Next()(但这是为资源管理服务,不是通用迭代) -
sync.Map.Range:接受func(key, value interface{}) bool
这些都不是 “Iterator 对象”,而是“一次性的遍历动作”。需要早停?靠回调返回 false;要并发安全?由调用方保证或加锁;要复用?重新调用函数即可 —— 简单、明确、无状态。











