Skip to content

Latest commit

 

History

History
66 lines (45 loc) · 2.53 KB

go-spec-exec.md

File metadata and controls

66 lines (45 loc) · 2.53 KB

程序的初始化和执行

零值

声明变量/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()并不会等待其他非主协程完成再退出。