在 Go 语言中,迭代器并非新概念,但现有的迭代器设计和使用方式各不相同。为了统一迭代器的标准化形式,Go 1.23 版本引入了标准迭代器,使得开发者只需掌握一种迭代器的定义和使用方式,便可以适应所有迭代器。
在 Go 1.23 中,迭代器是指符合以下三种函数签名之一的函数:
func(yield func() bool)
func(yield func(V) bool)
func(yield func(K, V) bool)
迭代器分为推迭代器(push iterator)和拉迭代器(pull iterator)。上述设计是典型的推迭代器,通过调用 yield
函数逐步推出一系列值。
func Backward[E any](s []E) func(yield func(int, E) bool) {
return func(yield func(int, E) bool) {
for i := len(s) - 1; i >= 0; i-- {
if !yield(i, s[i]) {
return
}
}
}
}
在 Go 1.23 中,for-range
循环得到了改进,新增了对函数类型的支持。这意味着我们可以使用 for-range
循环来接收迭代器推出的值。
package main
import "fmt"
func main() {
s := []string{"程序员", "陈明勇"}
for i, v := range Backward(s) {
fmt.Println(i, v)
}
}
// Backward 倒序迭代
func Backward[E any](s []E) func(yield func(int, E) bool) {
return func(yield func(int, E) bool) {
for i := len(s) - 1; i >= 0; i-- {
if !yield(i, s[i]) {
return
}
}
}
}
iter
包Go 1.23 版本新增了一个 iter
包,定义了两种迭代器类型:Seq
和 Seq2
,用于处理不同的迭代场景。
Seq[V any]
:推出单个元素,例如切片的索引或映射中的键。Seq2[K, V any]
:推出一对元素,例如切片中的索引和值,或者映射中的键值对。package main
import (
"fmt"
"iter"
)
type Set[E comparable] struct {
m map[E]struct{}
}
func NewSet[E comparable]() Set[E] {
return Set[E]{m: make(map[E]struct{})}
}
func (s Set[E]) Add(e E) {
s.m[e] = struct{}{}
}
func (s Set[E]) Remove(e E) {
delete(s.m, e)
}
func (s Set[E]) Contains(e E) bool {
_, ok := s.m[e]
return ok
}
func (s Set[E]) All() iter.Seq[E] {
return func(yield func(E) bool) {
for v := range s.m {
if !yield(v) {
return
}
}
}
}
func main() {
set := NewSet[string]()
set.Add("Go1.23")
set.Add("迭代器")
for v := range set.All() {
fmt.Println(v)
}
}
拉迭代器与推迭代器相反,由调用方主动请求数据。iter
包提供了 Pull
函数,可以将标准(推)迭代器转换为拉迭代器。
package main
import (
"fmt"
"iter"
)
type Set[E comparable] struct {
m map[E]struct{}
}
// ... 省略其他方法 ...
func (s Set[E]) All() iter.Seq[E] {
return func(yield func(E) bool) {
for v := range s.m {
if !yield(v) {
return
}
}
}
}
func main() {
set := NewSet[string]()
set.Add("Go1.23")
set.Add("迭代器")
next, stop := iter.Pull(set.All())
for {
v, ok := next()
if !ok {
break
}
fmt.Println(v)
stop()
}
}
随着迭代器的引入,slices
和 maps
包也新增了一些与迭代器一起使用的函数。这些函数的详细用法可以参考相应的包文档。
Go 1.23 版本通过引入标准迭代器,统一了迭代器的设计和使用方式,解决了各自为政的问题,进一步优化了 Go 的生态系统。虽然迭代器的引入可能会对代码可读性产生一定影响,但 Go 官方通过新增 iter
包和在 slices
、maps
包中提供便捷函数,简化了迭代器的使用。
相关链接引用:
如果您喜欢我的文章,请点击下面按钮随意打赏,您的支持是我最大的动力。
最新评论