Go不提供Iterator接口,应避免Java式迭代器;推荐用func(T)bool回调、可range数据源或chan T。标准库如filepath.Walk、sync.Map均采用此范式,兼顾安全、性能与Go习惯。

Go 里没有 Iterator 接口,别硬套 Java 那套
Go 语言设计上不鼓励面向对象的迭代器模式,标准库也没有 Iterator 接口。强行封装一个带 HasNext() + Next() 的结构体,反而会让代码更难读、更易出错。
真正符合 Go 习惯的做法是:用函数值(func(T) bool)做遍历回调,或直接返回 chan / range 友好结构。标准库如 sync.Map、container/list 全部走这条路。
- 常见错误:写个
type Iterator struct { items []T; idx int },再配Next() T和Done() bool—— 无法安全并发,越界 panic 难排查,且和range不兼容 - 正确姿势:把“怎么遍历”交给调用方决定,库只提供可 range 的数据源,或接受处理函数
- 性能影响:自定义
Iterator结构体多一次堆分配 + 方法调用开销;而闭包回调或 channel 在逃逸分析下常被优化掉
用 func(T) bool 实现安全可控的遍历
这是 Go 生态最主流的替代方案,filepath.Walk、sql.Rows.Scan、container/list.Front 后续链式遍历都用它——函数返回 false 即中断,天然支持早停,无状态,线程安全。
func (s *MySet) Range(f func(item string) bool) {
for _, item := range s.items {
if !f(item) {
return
}
}
}- 使用场景:需要条件过滤、提前退出、或遍历时可能修改底层集合(此时不能用
range原始切片) - 参数差异:
func(T) bool比func() (T, bool)更轻量,避免多次取地址或复制大结构体 - 容易踩的坑:在回调函数里对传入的
item取地址并保存(&item),会导致所有指针指向最后一个元素 —— 应该在循环体内显式拷贝:copyItem := item; f(©Item)
什么时候该用 chan T 而不是回调?
当遍历逻辑复杂、涉及异步、IO 或需要与 select 配合时,chan T 是更自然的选择。但要注意它默认是阻塞的,且不提供“是否结束”的信号,必须配合 close 和 range 使用。
立即学习“go语言免费学习笔记(深入)”;
func (s *MySet) Iterate() <-chan string {
ch := make(chan string)
go func() {
defer close(ch)
for _, item := range s.items {
ch <- item // 注意:若接收方不及时读,这里会卡住
}
}()
return ch
}- 常见错误:忘记
defer close(ch),导致接收方永远等不到 EOF;或在 goroutine 外提前返回未缓冲的 channel,引发 panic - 性能影响:每个
Iterate()调用都启一个 goroutine,高频调用需评估开销;小数据量不如回调函数高效 - 兼容性注意:channel 无法直接用于
range以外的控制流(比如 break 到外层循环),必须用for range或显式recv, ok :=
自定义集合想支持 range?实现 Len() 和 At(int) T 不够
Go 1.23 引入了 ~[]T 类型约束后,部分泛型集合可通过 type Collection[T any] interface { ~[]T } 让用户直接 range。但如果你封装的是非切片结构(比如跳表、B 树),唯一办法是暴露底层可 range 的视图,而不是“模拟”迭代器。
- 正确做法:提供
Items() []T(注意是拷贝!)或Keys() []string这类方法,让调用方自己range—— 清晰、零抽象泄漏、调试友好 - 为什么不要
At(i int) T+Len():这要求调用方手动写for i := 0; i ,失去 range 的安全性(越界检查)、简洁性和编译器优化机会 - 容易忽略的点:如果集合本身是线程不安全的,
Items()返回的切片仍共享底层数组指针 —— 必须用append([]T(nil), s.items...)显式深拷贝
事情说清了就结束。Go 的迭代逻辑从来不是“构造一个能走的机器”,而是“给调用方一条干净的路”。选回调、channel 还是切片,取决于你愿不愿意为那点抽象,承担额外的生命周期管理、并发风险和调试成本。










