go 1.22 关于 for 循环问题的困惑

在发布 go 1.22 版本时,注意到了 for 循环有一个变更,简单就是说从之前的共享变量,调整为每次执行循环步都会重新实例化变量,这样避免了闭包中共享变量导致的并发问题。 于是今天通过代码模拟发生了一个令人困惑的问题,不同的执行方式,导致不同的结果,相同的代码:

func main() {
	done := make(chan bool)

	values := []string{"chen", "ming", "yong"}
	for _, v := range values {
		go func() {
			fmt.Println(v)
			done <- true
		}()
	}

	// 结束前等待所有的 goroutine 执行成
	for _ = range values {
		<-done
	}
}

当我使用 go run . 打印结果的时候为 (这显然是不正常的):

❯ go run .
yong
yong
yong

但是当我使用 go run main.go 打印结果确是正常的。这是为什么,是 bug 吗?还是本应该如此:

❯ go run main.go
yong
ming
chen

同时提交了 issue : import/path: Loops no longer share loop variablesRunning them in different ways gives different results · Issue #69704 · golang/go · GitHub

有没有大佬解答一下小弟的困惑

6 个赞

这边建议问下gpt呢

1 个赞


我拿你代码试下你提到的两种情况没区别啊,你是不第一次没保存 :xhs_021:

2 个赞

保存了。应该是 go mod 的问题。我的 go mod 没有指定版本号。

1 个赞

确实,我把go.mod里面版本改到1.20之后结果和你主楼是一样的

2 个赞

我感觉应该是 bug,我电脑只安装了 go 的一个版本。但是忽略了 go mod 的版本,应该使用最新的版本。

1 个赞

看见你在 golang 提 bug 了啊。

借楼问一个问题,golang的反序列化方法,假如这是一个待解析的json
{
“id”: “1”,
“name”: “2”,
“email”: “3”
}

那么json.Unmarshal的第二个参数应该要传递一个指针类型的map或者结构体,结构体传引用类型好理解,但是map本身就是引用类型,为什么还要传一个引用类型的map呢,这不是多次一举么,gpt给我回答的等于没回答…

你这语法本身就有问题. 需要用到 数组元素 都是 传参 进去的. 而不是 直接获取 外界变量的. 我5年go开发

是的,感觉是一个问题。但是还没更新细节

不要纠结代码,我只是一个 demo 而已

没太明白你的描述呢。

新特性如果go.mod中golang的版本比较低是不会生效的,一般通过go run好像是可以生效的

1 个赞

go run . 会使用 go.mod 文件中的 go 版本来确定编译行为和标准库函数的使用。如果 go.mod 中没有指定 go 版本,Go 会选择一个默认的最低兼容版本来编译当前目录下的所有 main 包的文件。

go run main.go 也会使用 go.mod 中的版本来确定编译行为,但有时在没有 go.mod 的情况下,它可能使用当前环境中的 Go 编译器版本(即安装的 Go 版本)

go的1.23版本修改并发for对应的item问题,可能最低版本还是老版本所以全部打印一样数据

1 个赞

我一般不会使用go run .这种写法,一般都是有个main.go的入口,其他的文件和main.go不放在一起,或者main.go需要使用多个同文件夹的go文件,使用go run *.go的方式

了解指针吗,指向指针的指针。

知道go run .和go run main.go的编译行为是有差异的,同时go mod文件中的go版本号会影响编译器的行为,但是具体不是很了解。
请问您描述的这个差异,能给一个官方文档的链接吗?
想学习一下,谢谢

yong
yong
yong

这个不是正确输出吗

输入命令 go help run 有介绍如果没有mod指定版本将会使用什么样的顺序,第一个是自感知模块选取最低标准

可以试试
export GO111MODULE=off
go run .

export GO111MODULE=on
go run .
就可以看出效果,go文档有介绍自动寻版本顺序

2 个赞

好的,非常感谢