[译]Go的初始化及过程(Program initialization and execution)

原文链接

变量初始化

Go中变量通过以下几种方式分配空间:

  • 通过定义(var)
  • 通过new创建
  • 通过赋值(:=)
  • 通过字面合成(through a composite literal)
  • 通过调用make

当没有明确的初始化时,会被赋予默认值。所有的变量初始化值为其类型所对应的零值,即

  • boolean:false
  • integer:0
  • float:0.0
  • string:””
  • pointers/function/interface/slice/channel/map:nil

变量的初始化是递归地完成的,如对于一个数组,其默认值为各个元素的零值。

示例

以下定义效果相同:

var i int
var i int = 0

对象而言,以下3种方式定义亦等同

type T struct { i int; f float64; next *T }


//方式1
t := new(T)

//方式2
t.i == 0
t.f == 0.0
t.next == nil

//方式3
var t T

包的初始化

包级别的变量初始化顺序

  • 按出现的顺序从前往后初始化
  • 若某个变量需要依赖其它变量,则被依赖的变量先初始化

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

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

其初始化顺序为d,b,c,a

同时,变量也可以通过不带任何输入和输出参数的函数init来实现。init相关注意如下:

  1. 一个包可以出线多个init函数,一个源文件也可以包含多个init函数(Multiple such functions may be defined, even within a single source file. )。
  2. init函数在代码中不能被显示调用、不能被引用(赋值给函数变量),否则出现编译错误(The init identifier is not declared and thus init functions cannot be referred to from anywhere in a program.
    )。
  3. 如果当前包包含多个依赖包(import),则先初始化依赖包(If a package has imports, the imported packages are initialized before initializing the package itself. )。
  4. 如果当前包有多个init函数,首先按照源文件名的字典序从前往后执行,若一个文件中出现多个init,则按照出现顺序从前往后执行(initialized by assigning initial values to all its package-level variables followed by calling all init functions in the order they appear in the source, possibly in multiple files, as presented to the compiler.)。
  5. 一个包被引用多次,如 A import B,C import B,A import C,B被引用多次,但B包只会初始化一次( If multiple packages import a package, the imported package will be initialized only once. )。
  6. 引入包,不可出现死循坏。即A import B,B import A,这种情况编译失败( The importing of packages, by construction, guarantees that there can be no cyclic initialization dependencies.
    )。

  7. 包级别的变量初始化、init函数的执行,这两个操作会在goruntine 自己调用,且顺序调用,一次一个包(Package initialization—variable initialization and the invocation of init functions—happens in a single goroutine, sequentially, one package at a time.)。
  8. 一个init函数里可能会启动其它goroutine,即在初始化的同时启动新的goroutine。然而,初始化依旧是顺序的,即只有上一个init执行完毕,下一个才会开始( An init function may launch other goroutines, which can run concurrently with the initialization code. However, initialization always sequences the init functions: it will not invoke the next one until the previous one has returned.)。

程序执行(Program execution)

一个完整的Go程序会包含一个main包,main包中指定主函数main、及import需要的包。程序运行时,首先会执行主函数的初始化,然后运行main函数。
当main函数执行完毕时,程序退出,所有goroutine退出。即main函数结束后,不会等待所有的goroutines执行结束