声明变量/new()/创建新值/创建复合字面量/make(),即使没有显示提供初始化, 这些变量或值都会有个默认值。零值。
变量和值皆有其零值:
- false:bool
- 0:数值类型
- "":string
- nil:指针/func/interface/slice/channel/map
这些初始化是递归完成的,所以数组/结构体中,如果没有明确指明值,就会有一个默认值。
// 下面的声明是等价的
var i int
var i int = 0
特别说明:就算是结构体, 直接声明,里面的值如果没有特别指定,都是零值.
在包内部,包级别的变量会逐步初始化, 每个步骤都按声明顺序选择最早的变量,前提是这个变量没有依赖和没有初始化。
如何确定一个变量是否准备好初始化:先看有没有初始化表达式(没有就直接初始化, 有就先做表达式),再看初始化表达式有没有依赖的其他变量还未初始化 (有就初始化其他变量先)。
一步步,直到所有的包级别的变量全都初始化完 这个初始化的循环会走多次(因为是递归), 所有变量初始化完之前,程序是无效的。 多变量声明语句,如果右边是可返回多值的单表达式,那么认为这几个变量是一步中初始化的.
空白标识符也被认为是一个变量。 多个文件的变量,她们的声明顺序,取决于编译器处理顺序。 依赖分析并不取决于实际的变量值,而是源码中引用的词法. 这里面还有一些规则,具体可以查看spec.
包中可以用init()函数来初始化变量,这个init的约定是:
-
包块
-
无参无返回值
func init() { … }
一个包可以有多个init(),极端一点,一个源码文件都可以有多个init(), 包块的init标识符只能用于初始化,包块中定义其他init标识符是非法的. 首字母小写,意味着不能被其他包引用. 如有有导入其他包,那么其他包先初始化,之后再初始化本包。
一个包,不管是变量初始化还是init()初始化,都是在一个协程中,按顺序执行的。 而顺序是有编译器决定的.一个包被多个包引用,那么这个包也只会初始化一次. 初始化不能循环引用.
完成的程序会有一个main包,她导入其他包,还有一个main(), main函数是无参无返回值的.
func main() { … }
程序的执行是先初始化main包,然后调用main(), main()执行完程序就退出. main()并不会等待其他非主协程完成再退出。