Golang 1.22新特性

Golang 1.22 feature

Posted by alovn on March 1, 2024

本文介绍一下Go1.22比较重要的几个新特性。

for

Go1.22版本中最大的变化是对于for循环的,有两处较大的更新:

  1. 之前的for循环每次循环中的变量只创建一次,每次循环。go1.22版本开始,每次循环都会创建新的变量。
  2. for range 直接支持变量整数。

下面用示例演示,首先安装go1.22

1
2
go install golang.org/dl/go1.22.1@latest
go1.22.1 download

loopvar示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

import (
	"fmt"
	"sync"
)

func main() {
	wg := sync.WaitGroup{}
	wg.Add(3)
	arr := []int{1, 2, 3}
	for _, x := range arr {
		go func() {
			fmt.Println(x)
			wg.Done()
		}()
	}
	wg.Wait()
}
1
2
3
4
5
6
7
8
9
10
>go version
go version go1.20.2 darwin/arm64
>go run main.go
3
3
3
>go1.22.1 run main.go
3
1
2

上面示例可以看出,当使用go 1.20.2 版本执行时输出的都是3。这是因为变量x在各个迭代中只声明了一个变量,所以在每次迭代中的goroutine中输出的都是循环结束后的最后的值。这在golang中一直被称为for range的坑。

而当使用go 1.22.1版本执行则是分别输出的,这也就是说每次迭代的变量x都是一个新的变量。

这可能是一个潜在破坏式的更新。关于它的变更会在go.mod文件中版本为go1.22.0及之后的版本才会生效,当然如果直接使用go run执行也会直接应用新特性的。

range示例

1
2
3
4
5
6
7
8
9
10
11
package main

import (
	"fmt"
)

func main() {
	for x := range 3 {
		fmt.Println(x)
	}
}
1
2
3
4
>go1.22.1 run main.go
0
1
2

rand

Go1.22中新增了math/rand/v2包,这是Go第一次在标准库中添加v2的包。后续版本的更新中其它包也可能会引入v2版本。

增强路由匹配

Go1.22中的http.ServeMux功能增强:

  1. “POST /items/create” 将直接匹配到路径”/items/create”的POST请求。
  2. 路径支持参数匹配,例如/items/{id}的路径可以使用 Request.PathValue(“id”) 获取到URL路径中id的值。
  3. “…“通配符。例如”/files/{path…}”, 它必须放在末尾,表示匹配所有剩余的段。
  4. 若要匹配确切的路径,可以在路径末尾增加”{$}”,例如: “/exact/match/{$}”。

http路由匹配的变更,可以使用 GODEBUG 变量来控制,通过设置 httpmuxgo121=1 恢复为之前旧版本的路径匹配行为。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main

import (
	"fmt"
	"net/http"
)

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("POST /items/create", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, "created")
	})
	mux.HandleFunc("/items/{id}", func(w http.ResponseWriter, r *http.Request) {
		id := r.PathValue("id")
		fmt.Fprint(w, "you got id: "+id)
	})
	mux.HandleFunc("/files/{path...}", func(w http.ResponseWriter, r *http.Request) {
		path := r.PathValue("path")
		fmt.Fprint(w, "you got path: "+path)
	})
	mux.HandleFunc("/exact/match/{$}", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, "match")
	})
	http.ListenAndServe(":8086", mux)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
>GODEBUG="httpmuxgo121=0" go1.22.1 run main.go

>curl -X POST http://localhost:8086/items/create
created

>curl http://localhost:8086/items/123
you got id: 123

>curl http://localhost:8086/files/abc
you got path: abc

>curl http://localhost:8086/files/abc/def
you got path: abc/def

>curl http://localhost:8086/exact/match/ 
match

>curl http://localhost:8086/exact/match  
<a href="/exact/match/">Moved Permanently</a>.

>curl http://localhost:8086/exact/match/1
404 page not found