快看! Go 1.22 對for循環進行了兩個大更新
Go 1.22 版本于 2024 年 2 月 6 日正式向世界宣告了版本的發布 。
我們可以從官網下載1.22版本進行體驗,或者從 Go Playground上進行體驗最新語法
圖片
值得注意的是在語言層面上,這個版本對 for 循環進行了兩處更新:
- ? for循環的每次迭代都會定義新變量,而不再是共享一個變量
- ? 支持對整數范圍進行循環迭代
今天將以案例的方式對比下最新版本 for 循環的兩個更新點。
?? Let's Go!
循環不再共享循環變量
?? for在循環語義層面的坑
Go1.22之前版本for 循環聲明的變量只創建一次,并在每次迭代中進行更新,這會導致遍歷時訪問value時實際上都是訪問的同一個地址的值。
相信不少小伙伴都遇到過,特別是在初學Go的時候!
Go1.22之前版本
我們用官博文章中那個例子,稍微改進如下,并使用1.21版本運行
package main
import "fmt"
func main() {
done := make(chan bool)
values := []string{"xiao", "xu", "code"}
for _, v := range values {
go func() {
fmt.Println(v)
done <- true
}()
}
// 等待所有的 goroutine 執行結束
for _ = range values {
<-done
}
}
上述代碼運行結果如下所示:
code
code
code
這三個創建的 goroutine 都在打印同一個變量 v,所以它們通常會打印出 "code"、"code"、"code",而不是以某種順序打印出 "xiao"、"xu" 和 "code"。
?? 這就是共享循環變量造成的問題!
這個比較好理解,這個循環的 v 只創建一次,在每次循環的時候都會更新,而 閉包在訪問 v 時實際上都訪問的是同一個內存地址,所以最終打印的都是同一個值。
解決辦法:
在Go版本不變的情況下,可以通過下面兩種方式修改代碼避免這個問題。
1:將for循環中傳入v,代碼改造如下
values := []string{"xiao", "xu", "code"}
for _, v := range values {
go func(v string) {
fmt.Println( v)
done <- true
}(v)
}
2:在循環中重新定義一個變量進行再次賦值
values := []string{"xiao", "xu", "code"}
for _, v := range values {
value := v
go func() {
fmt.Println( value)
done <- true
}()
}
Go1.22版本
不過這個問題在1.22版本已經得到處理了,大家用這個版本的時候可以放心使用了,太爽了吧!
我們在1.22版本上運行和1.21一樣的代碼
package main
import "fmt"
func main() {
done := make(chan bool)
values := []string{"xiao", "xu", "code"}
for _, v := range values {
go func() {
fmt.Println(v)
done <- true
}()
}
// 等待所有的 goroutine 執行結束
for _ = range values {
<-done
}
}
上述代碼運行結果如下所示:
code
xiao
xu
for 循環的每次迭代都會創建新變量,每次循環迭代各自的變量,以避免意外共享錯誤。上面一模一樣的代碼,輸出結果不再是固定的 code。
支持整數范圍進行循環迭代
在 Go 1.22 版本之前, for range 僅支持對 array or slice、string、map 和 channel 類型的進行迭代。
而自 Go 1.22 版本起,新增了整數類型的迭代支持,我們能夠直接使用整數進行循環迭代。
下面同樣列舉不同版本的例子,看看差異性!
Go1.22之前版本
package main
import "fmt"
func main() {
for i := range 5 {
fmt.Println("小許code", i)
}
}
不支持遍歷整數范圍,這個range 5就直接提示報錯了,編譯當然有問題了
.\main.go:15:17: cannot range over 5 (untyped int constant)
Go1.22版本
package main
import "fmt"
func main() {
for i := range 5 {
fmt.Println("小許code", i)
}
}
上述代碼運行結果如下所示:
小許code 0
小許code 1
小許code 2
小許code 3
小許code 4
今天關于Go 1.22關于for循環的更新就介紹到這了,是不是覺得這個更新太棒啦!
注意了,面試的同學,如果沒有指定說明版本的話,還是需要注意下調整回之前的答案!