变量初始化有错误吗

时间:2019-04-28 07:19:32

标签: go initialization

作为spec of golang,我尝试编写测试代码。 正如规范所说,初始化顺序是 d,b,c,a ,我认为 b应该是4,c应该是5 ,但是我得到了 b == 5和c == 4 有问题吗?还是我误解了规格?

我尝试了以下go版本

go version go1.12.4 linux/amd64
package main

import "fmt"

var (
    a = c + b
    b = f()
    c = f()
    d = 3
)

func f() int {
    d++
    return d
}

func main() {
    fmt.Println("a", a)
    fmt.Println("b", b)
    fmt.Println("c", c)
    fmt.Println("d", d)
}

结果是

result:
a 9
b 5
c 4
d 5

期望 b = 4,c = 5

2 个答案:

答案 0 :(得分:0)

不,正如您自己说的那样,它是d,c,b,a

所以d为3

然后c调用f()并且d为4,因此c为4

接下来的b调用f()并且d为5,因此b为5

最后,a是c + b或9

和d由于f()的副作用最终以5结束

这是相关部分的编译器输出

如您所见,它先设置c(c(SB)),然后设置b,然后设置a

  0x004b 00075 (b2.go:6)  CALL  "".f(SB)
  0x0050 00080 (b2.go:6)  MOVQ  (SP), AX
  0x0054 00084 (b2.go:6)  MOVQ  AX, "".c(SB)
  0x005b 00091 (b2.go:5)  CALL  "".f(SB)
  0x0060 00096 (b2.go:5)  MOVQ  (SP), AX
  0x0064 00100 (b2.go:5)  MOVQ  AX, "".b(SB)
  0x006b 00107 (b2.go:4)  MOVQ  "".c(SB), CX
  0x0072 00114 (b2.go:4)  ADDQ  CX, AX
  0x0075 00117 (b2.go:4)  MOVQ  AX, "".a(SB)

(为了生成此输出,我使用了go tool compile -S -N abcd.go > abcd.s 实际的代码行编号来自略有简化的版本,其中删除了fmt import和print语句

这是go版本go1.11.4 linux / amd64

与go版本go1.12.4 linux / amd64尝试相同,结果相同

答案 1 :(得分:0)

TL; DR -是的,您的输出中有错误。这是运行您期望的输出的代码:https://play.golang.org/p/bNUISdsPKyU

一些背景。变量按d, b, c, a的顺序初始化。如果某个变量引用了另一个未初始化的变量,则Go推迟初始化,直到它知道所引用的未初始化变量。

在变量初始化过程的每个步骤中,问:此变量是否已准备好进行初始化?

我们怎么知道?

...如果程序包级别的变量尚未初始化并且没有初始化表达式或者其初始化表达式不依赖于未初始化的变量,则视为已准备好初始化...依赖性分析不依赖于该变量的实际值。变量,仅根据源中对它们的词汇引用进行传递性分析。

因此,如果var a = b,我们将不会初始化a,直到我们初始化b

让我们通过示例代码中的第一个变量进行交谈...

var (
    a = c + b
    // Is this var ready for initialisation? 
    // No. It depends on uninitialized variables `c` and `b`.
    // Go initialization will skip this var until it knows about its dependencies 

使用其余变量重复此过程,您将获得与Go编译器相同的结果。

这些步骤的概念性总结:

1. Try initialise `a`. It depends on uninitialized `b` and `c`. Skip!
2. Try initialise `b`. It depends on uninitialized `d`. Skip!
3. Try initialise `c`. It depends on uninitialized `d`. Skip!
4. Try initialise `d`. Success!
5. Try initialise `a`. It depends on uninitialized `b` and `c`. Skip!
6. Try initialise `b`. Success!
7. Try initialise `c`. Success!
8. Try initialise `a`. Success!

请注意宣布“成功!”的步骤顺序:d, b, c, a