关于golang:Go-113版本引入的bug你遇到过这个坑么

Bug

大家看看上面这段程序,思考下输入后果应该是什么?

func main() {
  n := 0

  f := func() func(int, int) {
    n = 1
    return func(int, int) {}
  }
  g := func() (int, int) {
    println(n)
    return 0, 0
  }

  f()(g())
}

先思考几秒钟。。。


在Go 1.13版本之前,上述程序打印的后果是

1

在Go 1.13版本开始,上述程序打印的后果是

0

从习惯认知来看,编译器应该依照如下程序执行

  • step 1: evaluate f(),此时变量n的值为1
  • step 2: evaluate g(),此时打印n时,因为step 1曾经把n批改为1了,所以应该打印1
  • step3: 依据step 1和step 2的后果,执行最终的函数调用

Go编译器其实也是遵循这个设计的,官网文档的形容如下:

At package level, initialization dependencies determine the evaluation order of individual initialization expressions in variable declarations.

Otherwise, when evaluating the operands of an expression, assignment, or return statement, all function calls, method calls, and communication operations are evaluated in lexical left-to-right order.

最初一句的表述能够晓得,在执行函数调用时,对于函数的操作数,语法上是依照从左到右的程序进行解析的。

这个bug其实是Google Go团队成员Matthew Dempsky提出来的,Go官网认领了这个bug,这个bug产生的起因也很显著,就是先执行了g(),而后执行的f()

This is because we rewrite f()(g()) into t1, t2 := g(); f()(t1, t2) during type checking.

gccgo compiles it correctly.

@cuonglm Yeah, rewriting as t0 := f(); t1, t2 := g(); t0(t1, t2) instead seems like a reasonable quick fix to me. I think direct function calls and method calls are probably the most common case though, so we should make sure those are still handled efficiently.

Longer term, I think we should probably incorporate order.go directly into unified IR.

目前这个bug的影响范畴如下:

  • Go 1.13版本开始引入的这个bug,目前曾经被修复,预计在1.19版本公布。
  • 只有官网的编译器gc有这个bug,如果你应用的是gccgo编译器,也不会有这个问题。
  • 只对多个参数的函数调用才会有这个bug,比方上面这个例子f()的后果是一个函数,该函数只有1个参数,就不会有本文提到的这个bug。
package main

func main() {
    n := 0

    f := func() func(int) {
        n = 1
        return func(int) {}
    }
    g := func() int {
        println(n)
        return 0
    }

    f()(g())
}

下面程序执行后果是1

举荐浏览

  • 泛型

    • 泛型:Go泛型入门官网教程
    • 泛型:一文读懂Go泛型设计和应用场景
    • 泛型:Go 1.18正式版本将从规范库中移除constraints包
    • 泛型:什么场景应该应用泛型
  • Fuzzing

    • Fuzzing: Go Fuzzing入门官网教程
    • Fuzzing: 一文读懂Go Fuzzing应用和原理
  • 工作区模式

    • Go 1.18:工作区模式workspace mode简介
    • Go 1.18:工作区模式最佳实际

开源地址

文章和示例代码开源在GitHub: Go语言高级、中级和高级教程。

公众号:coding进阶。关注公众号能够获取最新Go面试题和技术栈。

集体网站:Jincheng’s Blog。

知乎:无忌

References

  • https://twitter.com/go100and1…
  • https://github.com/golang/go/…
  • https://go.dev/ref/spec#Order…

【腾讯云】云产品限时秒杀,爆款1核2G云服务器,首年50元

阿里云限时活动-2核2G-5M带宽-60G SSD-1000G月流量 ,特惠价99元/年(原价1234.2元/年,可以直接买3年),速抢

本文由乐趣区整理发布,转载请注明出处,谢谢。

您可能还喜欢...

发表评论

您的电子邮箱地址不会被公开。

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据