Situation:
Go包A由3.go
个文件组成,我在每个文件中使用另一个包B的函数.我必须在每个文件的开头导入B包.
Question:个
包B实际上是初始化了3次还是只初始化了1次?
Situation:
Go包A由3.go
个文件组成,我在每个文件中使用另一个包B的函数.我必须在每个文件的开头导入B包.
Question:个
包B实际上是初始化了3次还是只初始化了1次?
简短回答:初始化只执行一次.
详细答案:引用相关规范部分-Program execution:
没有导入的包是通过将初始值赋给它的所有包级变量,然后使用名称和签名调用任何包级函数来初始化的
func init()
在其来源中定义.名称为
init
的包范围或文件范围标识符只能声明为具有此签名的函数.即使在单个源文件中也可以定义多个这样的函数;它们以未指定的顺序执行.在包中,根据引用顺序初始化包级变量,并确定常量值:如果A的初始化式依赖于B,则在B之后设置A.依赖分析不依赖于要初始化的项的实际值,只依赖于它们在源代码中的出现.如果A的值包含提及B,包含其初始化式提及B的值,或递归提及提及B的函数,则A依赖于B.如果这样的依赖形成一个循环,那就是错误的.如果两个项不是相互依赖的,则它们将按照它们在源代码中出现的顺序进行初始化,可能在呈现给编译器的多个文件中.因为依赖关系分析是针对每个包进行的,所以如果A的初始值设定项调用在另一个引用B的包中定义的函数,它可能会产生未指定的结果.
不能从程序中的任何位置引用
init
函数.特别是,不能显式调用init
,也不能将指向init
的指针赋给函数变量.如果包具有导入,则在初始化包本身之前初始化导入的包.如果多个包导入一个包P,P将只初始化一次.
通过构造导入包,可以保证在初始化过程中不会有循环依赖关系.
一个完整的程序是通过将一个称为main package的未导入包与它导入的所有包进行传递链接而创建的.主包必须有包名
main
,并声明一个不带参数且不返回值的函数main
.func main() { … }
程序执行通过初始化主程序包然后调用函数
main
开始.当函数main
返回时,程序退出.它不等待其他(非主)Goroutine完成.包初始化-变量初始化和
init
个函数的调用-在单个Goroutine中顺序进行,一次一个包.函数init
可能会启动其他Goroutine,它们可以与初始化代码同时运行.但是,初始化总是对init
个函数进行排序:在前一个函数返回之前,它不会启动下一个init
个函数.