【发布时间】:2018-11-15 08:30:47
【问题描述】:
情况:
一个 Go 包 A 由 3 个 .go 文件组成,我在每个文件中使用另一个包 B 中的函数。我必须在每个文件的开头导入包B。
问题:
B 包实际上是初始化了 3 次还是只初始化了 1 次?
【问题讨论】:
标签: go
情况:
一个 Go 包 A 由 3 个 .go 文件组成,我在每个文件中使用另一个包 B 中的函数。我必须在每个文件的开头导入包B。
问题:
B 包实际上是初始化了 3 次还是只初始化了 1 次?
【问题讨论】:
标签: go
简答:初始化只会执行一次。
长答案:引用相关规范部分 - Program execution:
一个没有导入的包通过为其所有包级变量分配初始值,然后调用具有名称和签名的任何包级函数来初始化
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。
【讨论】: