1. 程式人生 > >GO語言規範-程式的初始化與執行

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完成。