快看! 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循环的更新就介绍到这了,是不是觉得这个更新太棒啦!

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

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

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

相关推荐
爱勇宝7 小时前
第 1 章:别把“需求文档”当成真正的需求
前端·后端·程序员
IT_陈寒12 小时前
闭包陷阱让我加了两天班,JavaScript你真行
前端·人工智能·后端
易协同低代码13 小时前
通达OA核心类库TD类深度解析
后端
Gopher_HBo13 小时前
Go语言学习笔记(十八)Gin处理Session
后端
谭光志14 小时前
工具塞满上下文窗口怎么办?深度拆解 AI Agent Tool Search 按需加载实现原理
前端·后端·ai编程
她说..14 小时前
Java 默认值设置方式
java·开发语言·后端·springboot
foggyprojects14 小时前
从0开始,一句话启动AI DataAgent
后端·数据分析·ai编程
郡杰14 小时前
一些基础和问题解决
后端
陈随易14 小时前
前端项目部署只要30秒
前端·后端·程序员
YIAN14 小时前
从零手写文件读取 MCP 服务:一文吃透 Model Context Protocol 全链路通信原理
前端·后端·mcp