21

情况:

Go 包A由 3 个文件组成,我在每个文件中.go使用另一个包B中的函数。我必须在每个文件的开头导入包B。

问题:

B实际初始化了 3 次还是仅初始化了 1 次?

4

1 回答 1

37

简短的回答:初始化将只执行一次。

长答案:引用相关规范部分 -程序执行

一个没有导入的包通过为其所有包级变量分配初始值,然后调用任何具有名称和签名的包级函数来初始化

func init()

在其来源中定义。具有名称的包范围或文件范围标识符init只能声明为具有此签名的函数。即使在一个源文件中,也可以定义多个这样的函数;它们以未指定的顺序执行。

在一个包内,初始化包级变量,并确定常量值,根据引用顺序:如果A的初始化器依赖于B,则A将设置在B之后。依赖分析不依赖于实际值正在初始化的项目,仅在它们在源中出现时。如果 A 的值包含对 B 的提及、包含其初始值设定项提及 B 的值或提及提及 B 的函数,则 A 依赖于 B。如果这样的依赖形成一个循环,那就是错误的。如果两个项目不相互依赖,它们将按照它们在源中出现的顺序进行初始化,可能在多个文件中,如呈现给编译器的那样。由于依赖关系分析是针对每个包进行的,因此如果 A 的初始化程序调用另一个包中定义的引用 B 的函数,则可能会产生未指定的结果。

init不能从程序中的任何地方引用函数。特别是,init不能显式调用,也不能将指针init分配给函数变量。

如果包有导入,则在初始化包本身之前初始化导入的包。如果多个包导入一个包 P,则 P 只会被初始化一次。

包的导入,通过构造,保证了初始化中不会有循环依赖。

一个完整的程序是通过将一个单独的、未导入的包(称为主包)与其导入的所有包连接起来的,传递性的。主包必须有包名main并声明一个main不带参数且不返回值的函数。

func main() { … }

程序执行首先初始化主包,然后调用函数main。当函数main返回时,程序退出。它不会等待其他(非主)goroutine 完成。

包初始化——变量初始化和init函数调用——发生在一个 goroutine 中,顺序地,一次一个包。一个init函数可能会启动其他 goroutine,这些 goroutine 可以与初始化代码同时运行。然而,初始化总是对函数进行排序:在前一个函数返回之前,init它不会开始下一个函数。init

于 2013-07-18T20:36:15.257 回答