情况:
Go 包A由 3 个文件组成,我在每个文件中.go
使用另一个包B中的函数。我必须在每个文件的开头导入包B。
问题:
包B实际初始化了 3 次还是仅初始化了 1 次?
简短的回答:初始化将只执行一次。
长答案:引用相关规范部分 -程序执行:
一个没有导入的包通过为其所有包级变量分配初始值,然后调用任何具有名称和签名的包级函数来初始化
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