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