GO语言规范-程序的初始化与执行

GO语言规范-程序的初始化与执行

零值

When storage is allocated for a variable, either through a declaration or a call of new, or when a new value is created, either through a composite literal or a call of make, and no explicit initialization is provided, the variable or value is given a default value. Each element of such a variable or value is set to the zero value for its type: false for booleans, 0 for numeric types, “” for strings, and nil for pointers, functions, interfaces, slices, channels, and maps. This initialization is done recursively, so for instance each element of an array of structs will have its fields zeroed if no value is specified.

以下两个简单的声明是一样的:

var i int
var i int = 0

有如下的声明

type T struct { i int; f float64; next *T }
t := new(T)

那么

t.i == 0
t.f == 0.0
t.next == nil

上面的结果对以下的声明也是同样的

var t T

包的初始化

Within a package, package-level variables are initialized in declaration order but after any of the variables they depend on.

更恰当的说,一个包级别的变量如果

  • 还没有被初始化,并且
  • 没有初始化表达式,或其初始化表达式不依赖于未初始化的变量
    它就被认为是可以被初始化的。初始化过程不断重复对下一个最先定义且可被初始化的包级别变量进行初始化,直到没有变量可被初始化为止。

如果初始化过程结束后,还有未初始化的变量,则这些变量可能是一个或多个初始化循环的一部分,此时程序是不可用的。

The declaration order of variables declared in multiple files is determined by the order in which the files are presented to the compiler: Variables declared in the first file are declared before any of the variables declared in the second file, and so on.

Dependency analysis does not rely on the actual values of the variables, only on lexical references to them in the source, analyzed transitively. For instance, if a variable x’s initialization expression refers to a function whose body refers to variable y then x depends on y. Specifically:

  • A reference to a variable or function is an identifier denoting that variable or function.
  • A reference to a method m is a method value or method expression of the form t.m, where the (static) type of t is not an interface type, and the method m is in the method set of t. It is immaterial whether the resulting function value t.m is invoked.
  • A variable, function, or method x depends on a variable y if x’s initialization expression or body (for functions and methods) contains a reference to y or to a function or method that depends on y.

Dependency analysis is performed per package; only references referring to variables, functions, and methods declared in the current package are considered.

例如,给定以下声明

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

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

则初始化顺序是: d, b, c, a.

变量可以由包范围内的名为init的函数初始化,这个函数没有参数也没有返回值 。

func init() { … }

一个包中可能有多个此函数,甚至一个源文件也可能有多个。在包范围内init标识符只能用于声明init函数,而且这个标识符本身不会被声明,因此init函数不能在程序的任何地方被引用。

一个没有导入的包的初始化,是通过对它的所有包级别变量赋值,接着按照源码文件(可能是多个)中出现的顺序调用所有的init函数来进行的。如果一个包有导入,则被导入的包会先初始化。如果多个包导入了同一个包,则被导入的包只进行一次初始化。 The importing of packages, by construction, 保证不会有循环初始化依赖。

包的初始化—变量的初始化和init函数的调用—发生在一个goroutine中,接顺序,一次一个包。而init函数可能会发起另外的goroutine,可能会与初始化代码并发执行。但是初始化总是顺序执行init函数:只有一个返回了才调用下一个。

To ensure reproducible initialization behavior, build systems are encouraged to present multiple files belonging to the same package in lexical file name order to a compiler.

程序执行

完整的程序是通过链接一个独立未被导入的称为主包的包及其所导入的所有的包而创建的。主包必须是一个名字为main的包,并且声明了一个没有参数和返回值的函数main。

func main() { … }

程序通过初始化main包并调用main函数来开始执行。当main函数执行返回,程序就退出了。不会等待其他的goroutines完成。

猜你喜欢

转载自blog.csdn.net/finalday/article/details/82797903