2024年5月22日,Go 1.23版本[1]功能特性正式冻结,后续将只改bug,不增加新feature。
对Go团队来说,这意味着开始了Go 1.23rc1的冲刺,对我们普通Gopher而言,这意味着是时候对Go 1.23新增的功能做一些前瞻了!
在Go没有发布Go 1.23rc1之前,我们至少可以通过以下两种渠道体验Go 1.23的最新特性:
通过go install安装tip版本;
使用Go playground[2]在线体验。
注:关于Go tip的安装方法以及Go playground在线体验的详细说明,这里就不赘述了,《Go语言第一课》[3]专栏的“03|配好环境:选择一种最适合你的Go安装方法[4]”有系统全面的讲解,欢迎订阅阅读。
按照Go Release cycle[5],Go 1.23将于2024年8月发布!因此目前为时尚早,下面列出的有些变化最终不一定能进入到Go 1.23的最终版本中,有小概率被revert的可能或者推迟到下一个版本(Go 1.24),所以切记一切变更点要以最终Go 1.23版本发布时为准。
1. 语言变化
Go 1.23语言变化较少,除了range over func试验特性转正,再有就是几个悬而未决的spec变更。
1.1 range over func试验特性转正(61405[6])
Go 1.22版本[7]引入了range over func[8]试验特性,通过GOEXPERIMENT=rangefunc,可以实现函数迭代器。这一特性在Go 1.23版本正式转正,下面代码可以直接使用Go 1.23编译运行:
// go1.23-foresight/lang/range-over-function-iterator/main.go
package main
import "fmt"
func Backward[E any](s []E "E any") func(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
}
}
return
}
}
func main() {
sl := []string{"hello", "world", "golang"}
for i, s := range Backward(sl) {
fmt.Printf("%d : %s\n", i, s)
}
}
使用Go 1.23运行上述示例:
$go run main.go
2 : golang
1 : world
0 : hello
range over func可以提供一种统一、高效的迭代方式, 为泛型后的自定义容器类提供统一的迭代接口,同时也可以替代部分现有API返回切片的做法, 改为通过迭代器的形式改进性能(通过编译器的优化),甚至还可以为函数式编程风格提供标准迭代机制。
rang over func机制的实现是通过编译器在源码层面的转换,其转换形式大致如下:
// 单循环变量
for x := range f1 {
...
}
将被转换为:
f1(func(x T) bool {
...
})
而另外一种常见的双循环变量形式的for range:
for expr1, expr2 = range f2 {
...
}
将被转换为:
f2(func(#p1 T1, #p2 T2) bool {
expr1, expr2 = #p1, #p2
...
})
前提是:f1和f2分别要满足标准库中iter包中的下面函数原型形式:
// $GOROOT/src/iter/iter.go
type Seq[V any] func(yield func(V) bool) bool
type Seq2[K, V any] func(yield func(K, V) bool) bool
此外,for range循环体中如果有break,将被转换为f1/f2中的return false,而如果有continue,则会被转换为return true。当然这只是大致的形式,实际的转换远比这个要复杂很多,要考虑的情况也是十分复杂。更为具体、复杂的转换可以参考Go编译器的实现源码rewrite.go[9]
函数迭代器虽然转正,但肯定尚未成熟,后