首先来看两个golang的示例程序:

示例1:

package main

import “fmt”
var (
    a int = b + 1
    b int = 1
)

func main() {
    fmt.Println(a)
    fmt.Println(b)
}

示例2:

package main

import "fmt"

func main() {
    var (
        a int = b + 1
        b int = 1
    )
    fmt.Println(a)
    fmt.Println(b)
}

大家想一下,这两个程序的输出是否一样呢?当然不一样啦,要是一样的话,我写这两段程序就没意义了。

示例1 输出:

1
2

示例2 输出:

# command-line-arguments
./interest.go:7: undefined: b

输出不同的原因:不同作用域类型的变量初始化顺序不同。

示例2中的变量a,b是函数作用域内的局部变量,初始化顺序:从左到右、从上到下。

func f() int { fmt.Println("f"); return 1 }
func g() int { fmt.Println("g"); return 2 }
func h() int { fmt.Println("h"); return 3 }
func main() {
    var (
        a int = f()
        b int = g()
        c int = h()
    )
    fmt.Println(a, b, c)
}

输出:

f
g
h
1 2 3

但是对于示例1中package级别的变量,初始化顺序与初始化依赖有关。

package main

import "fmt"
var (
    a = c — 2
    b = 2
    c = f()
)
func f() int {
    fmt.Printf("inside f and b = %d\n", b)
    return b + 1
}
func main() {
    fmt.Println(a)
    fmt.Println(b)
    fmt.Println(c)
}

上述代码的初始化顺序:

  1. b在第一个初始化周期(initialization cycle)被初始化,因为变量b不依赖任何其他变量;
  2. c在第二个初始化周期被初始化,因为a的初始化依赖c;
  3. a在第三个初始化周期被初始化;

输出:

inside f and b = 2
1
2
3

在每一个初始化周期,运行时(runtime)会挑选一个没有任何依赖的变量初始化,该过程一直持续到所有的变量均被初始化或者出现依赖嵌套的情形:

package main

import "fmt"
var (
    a = b
    b = c
    c = f()
)
func f() int {
    return a
}
func main() {
    fmt.Println(a, b, c)
}

编译器会提示错误:“initialization loop”

同一个package下多个文件的变量初始化依赖也遵循相同的规则:

tools.go

package main
import "fmt"
var (
    a = c — 2
    b = 2
)
func main() {
    fmt.Println(a)
    fmt.Println(b)
    fmt.Println(c)
}

utils.go

package main
var c = f()
func f() int {
    return b + 1
}

输出:

1
2
3


想了解更多golang编程相关知识,请扫描上面二维码关注微信公众号 bloomingTony