你好,我是陈明勇,一名热爱技术、乐于分享的开发者,同时也是开源爱好者。
成功的路上并不拥挤,有没有兴趣结个伴?
关注我,加我好友,一起学习一起进步!
个人网站:https://chenmingyong.cn
文章持续更新,如果本文能让您有所收获,欢迎点赞收藏加关注本号。 微信阅读可搜《程序员陈明勇》。 这篇文章已被收录于 GitHub https://github.com/chenmingyong0423/blog,欢迎大 家Star 催更并持续关注。
前言
Go 1.23
版本在北京时间 2024 年 8 月 14 日凌晨 1:03 发布。该版本带来了多项重大更新,具体内容可以参考我之前的文章:Go 1.23 版本发布啦,这些重大更新你一定要知道!。本文将重点介绍 iterator
标准迭代器。
准备好了吗?准备一杯你最喜欢的咖啡或茶,随着本文一探究竟吧。
为什么引入标准迭代器
迭代器在 Go
语言中并非新概念,实际上,它一直存在于 Go
的生态系统中。如果你经常使用 Go
标准库,可能已经注意到某些库提供了迭代器的实现,例如:bufio.Scanner、database.Rows、filepath.Walk(Dir)、flag.Visit 和 sync.Map.Range 等。那么为什么 Go
官方仍然会提供统一的迭代器标准呢?主要原因在于现有的迭代器设计和使用方式各不相同。当我们使用一个新库的迭代器时,通常需要学习它的具体使用方法。如果能够统一迭代器的标准化形式,我们只需掌握标准迭代器的定义和使用方式,便可以适应所有迭代器。
迭代器
在 Go 1.23
中,迭代器 实际上是指符合以下三种函数签名之一的函数:
func(yield func() bool)
func(yield func(V) bool)
func(yield func(K, V) bool)
如果一个函数或方法返回的值符合上述形式之一,那么该返回值就可以被称为 迭代器。
迭代器又分为 推迭代器 和 拉迭代器,上面这种设计是典型的 推迭代器,通过调用 yield
函数逐步推出一系列值,yield
函数返回 bool
,决定是否继续执行推出操作。
代码示例:
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
}
}
}
}
在这个示例中,该迭代器会倒序遍历 s
切片中的元素,并通过 yield
函数将每个元素推出去。如果 yield
返回 false
,遍历将提前终止。
Range Over Function Types(对函数类型的遍历)
看了前面的迭代器实现后,你是否有一头雾水:迭代器通过调用 yield
函数逐步推出元素值,那么我们该如何接收迭代器推出的值呢?答案是使用 for-range
循环。
在 Go 1.23
版本中,for-range
循环中的范围表达式得到了改进。此前,范围表达式仅支持 array
(数组)、slice
(切片) 和 map
(映射) 等类型,而从 Go 1.23
开始,新增了对函数类型的支持。不过,函数类型必须是前面所提到的三种类型之一,也就是函数需要实现迭代器。
代码示例:
package main
import "fmt"
func main() {
s := []string{
"程序员", "陈明勇"}
for i, v := range Backward(s) {
fmt.Println(i