快看! 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版本运行

go 复制代码
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
    }
}

上述代码运行结果如下所示:

css 复制代码
code
code
code

这三个创建的 goroutine 都在打印同一个变量 v,所以它们通常会打印出 "code"、"code"、"code",而不是以某种顺序打印出 "xiao"、"xu" 和 "code"。

🚩 这就是共享循环变量造成的问题!

这个比较好理解,这个循环的 v 只创建一次,在每次循环的时候都会更新,而 闭包在访问 v 时实际上都访问的是同一个内存地址,所以最终打印的都是同一个值。

解决办法:

在Go版本不变的情况下,可以通过下面两种方式修改代码避免这个问题。

1:将for循环中传入v,代码改造如下

go 复制代码
values := []string{"xiao", "xu", "code"}
for _, v := range values {
	go func(v string) {
		fmt.Println( v)
		done <- true
	}(v)
}

2:在循环中重新定义一个变量进行再次赋值

go 复制代码
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一样的代码

go 复制代码
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
    }
}

上述代码运行结果如下所示:

css 复制代码
code
xiao
xu

for 循环的每次迭代都会创建新变量,每次循环迭代各自的变量,以避免意外共享错误。上面一模一样的代码,输出结果不再是固定的 code。

支持整数范围进行循环迭代

在 Go 1.22 版本之前, for range 仅支持对 array or slice、string、map 和 channel 类型的进行迭代。

而自 Go 1.22 版本起,新增了整数类型的迭代支持,我们能够直接使用整数进行循环迭代。

下面同样列举不同版本的例子,看看差异性!

Go1.22之前版本

go 复制代码
package main

import "fmt"

func main() {
	for i := range 5 {
		fmt.Println("小许code", i)
	}
}

不支持遍历整数范围,这个range 5就直接提示报错了,编译当然有问题了

go 复制代码
.\main.go:15:17: cannot range over 5 (untyped int constant)

Go1.22版本

go 复制代码
package main

import "fmt"

func main() {
	for i := range 5 {
		fmt.Println("小许code", i)
	}
}

上述代码运行结果如下所示:

css 复制代码
小许code 0
小许code 1
小许code 2
小许code 3
小许code 4

今天关于Go 1.22关于for循环的更新就介绍到这了,是不是觉得这个更新太棒啦!

注意了,面试的同学,如果没有指定说明版本的话,还是需要注意下调整回之前的答案!

欢迎点赞 👍、收藏 💙、关注 💡 三连支持一下~🎈🎈

知道的越多,不知道的也越多,我是小许,下期见~🙇💻

相关推荐
ajsbxi4 分钟前
苍穹外卖学习记录
java·笔记·后端·学习·nginx·spring·servlet
颜淡慕潇1 小时前
【K8S问题系列 |1 】Kubernetes 中 NodePort 类型的 Service 无法访问【已解决】
后端·云原生·容器·kubernetes·问题解决
尘浮生2 小时前
Java项目实战II基于Spring Boot的光影视频平台(开发文档+数据库+源码)
java·开发语言·数据库·spring boot·后端·maven·intellij-idea
尚学教辅学习资料2 小时前
基于SpringBoot的医药管理系统+LW示例参考
java·spring boot·后端·java毕业设计·医药管理
monkey_meng3 小时前
【Rust中的迭代器】
开发语言·后端·rust
余衫马3 小时前
Rust-Trait 特征编程
开发语言·后端·rust
monkey_meng3 小时前
【Rust中多线程同步机制】
开发语言·redis·后端·rust
paopaokaka_luck8 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
码农小旋风9 小时前
详解K8S--声明式API
后端
Peter_chq9 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端