golang1.22新特性 a year ago
前言
自go1.21,历时6个月,golang官方发布了go1.22。
相比之前的版本,这次更新主要体现在工具链,runtime还有标准库
主要更新如下:
从语言层面来看for loop有2大更新
1, go1.22之前,for循环的变量只创建一次,然后在每次迭代的时候来更新此变量,这样就会有个潜在的bug, 来看下面的示例代码:
package main
import (
"fmt"
"time"
)
func main() {
for i := 0; i < 10; i++ {
go func() {
fmt.Println(i)
}()
}
time.Sleep(time.Second)
}
在1.22之前运行是下面的结果:
golang1.22后,这个bug就被消除了
2, for range可以用在整型上
package main
import "fmt"
func main() {
for x := range 10 {
fmt.Println(x)
}
}
此外go1.22还可以提前体验range-over-function iterators, 编译的时候需要使用GOEXPERIMENT=rangefunc
开启, 格式如下:
GOEXPERIMENT=rangefunc go install my/program
GOEXPERIMENT=rangefunc go build my/program
GOEXPERIMENT=rangefunc go test my/program
GOEXPERIMENT=rangefunc go test my/program -bench=.
请看这个示例:
在goland里是报错的,因为此特性还没“真正”的被引入go1.22
我们可以按照IDE的提示,点击enable然后直接run
我们换个方法,尝试从terminal中运行:
Runtime
一句话总结:提升了CPU的性能,降低了内存使用率, 同时将原来16字节的对齐方式改为了8个字节(如果你学过C++ 的struct,就知道sturct字段的顺序会影响Object的大小,其原因就是字节对齐)
Compiler
使用PGO性能会显著提升
以下是个demo, 运行时go run xxx.go
即可
package main
import (
"fmt"
"log"
"net/http"
_ "net/http/pprof"
)
func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, you've requested: %s\n", r.URL.Path)
}
func main() {
http.HandleFunc("/", helloHandler)
fmt.Println("Starting server at port 10097")
if err := http.ListenAndServe(":10097", nil); err != nil {
log.Fatal(err)
}
}
Core library
math/rand/v2
math/rand/v2
是Go 1.22第一个v2版本被引入的pkg,相比math/rand
的变化在#61716中有详细描述。
最重要的变化包括:
- 1. 在math/rand(被math/rand弃用)中的Read方法在math/rand/v2中不再继续使用(在math/rand中仍可用)。大部分调用Read的地方应使用crypto/rand的Read。另外,也可以使用Uint64方法自定义一个Read。
- 2. 通过顶级函数访问的全局生成器无条件地随机种子。因为API保证了没有固定的结果序列,所以现在可以进行如每个线程的随机生成器状态这样的优化。
- 3. Source接口现在有一个单独的Uint64方法;没有Source64接口。
- 4. 许多方法现在使用更快的算法,过去在math/rand中无法采用,因为它们改变了输出流。
- 5. 在math/rand/v2中,math/rand的顶级函数和方法Intn, Int31, Int31n, Int63, and Int64n的名字更加符合习惯,分别变成了IntN, Int32, Int32N, Int64, 和Int64N。还新增了顶级函数和方法Uint32, Uint32N, Uint64, Uint64N和UintN。
- 6. 新的通用函数N与Int64N或Uint64N类似,但适用于任何整数类型。例如,从0到5分钟的随机持续时间为
rand.N(5*time.Minute)
。 - 7. 由
math/rand
的Source提供的Mitchell & Reeds LFSR生成器已被两个更现代的伪随机生成器源取代:ChaCha8 and PCG。ChaCha8是一个新的,密码学强大的随机数生成器,其效率大致类似于 PCG。ChaCha8是math/rand/v2
顶级函数使用的算法。截至Go 1.22,math/rand
的顶级函数(在没有显式设种的情况下)和Go运行时也使用ChaCha8进行随机性。
来看下面这个示例:
package main
import (
"fmt"
"math/rand/v2"
"time"
)
func main() {
for _ = range 10 {
duration := rand.N(time.Minute * 5)
fmt.Println(duration)
time.Sleep(time.Millisecond * 100)
}
}
go/version
package main
import (
"fmt"
"go/version"
)
func main() {
current := "go1.21"
previous := "go1.20"
for _, v := range []string{current, previous} {
if !version.IsValid(v) {
fmt.Println("Versions are not changed")
return
}
}
switch version.Compare(current, previous) {
case 0:
fmt.Println("Versions are the same")
case 1:
fmt.Println("Current version is newer")
case -1:
fmt.Println("Current version is older")
}
}
slices
新的函数Concat用于连接多个切片。
那些会缩小切片大小的函数(Delete
、DeleteFunc
、Compact
、CompactFunc
以及Replace
)现在将新长度与老长度之间的元素置零。
如果参数i超出范围,Insert
现在总会触发panic。之前如果没有要插入的元素,它在这种情况下不会触发panic。
1.22 slices的api如下:
来看几个示例:
1, Concat
package main
import (
"fmt"
"slices"
)
func main() {
xs := []int{1, 2, 3, 4, 5}
ys := []int{6, 7}
zs := []int{8, 9, 10}
all := slices.Concat(xs, ys, zs)
fmt.Println(all)
}
2, Delete
package main
import (
"fmt"
"slices"
)
func main() {
xs := []int{1, 2, 3, 4, 5}
ys := slices.Delete(xs, 1, 3)
fmt.Println(ys)
}
3, Insert
package main
import (
"fmt"
"slices"
)
func main() {
xs := []int{1, 2, 3, 4, 5}
ys := slices.Insert(xs, 1, 3)
fmt.Println(ys)
}
4, Replace
package main
import (
"fmt"
"slices"
)
func main() {
xs := []int{1, 2, 3, 4, 5}
zs := slices.Replace(xs, 1, 4, 2)
fmt.Println(zs)
}
net/http
net/http也增加了些新特性,不过我还是习惯用gin。
package main
import (
"fmt"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("POST /users", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Create User"))
})
mux.HandleFunc("/users/{id}", func(w http.ResponseWriter, r *http.Request) {
userId := r.PathValue("id")
fmt.Fprintf(w, "User ID: %s ", userId)
})
http.ListenAndServe(":10097", mux)
}
想了解更多,请仔细阅读官方文档:https://tip.golang.org/doc/go1.22