Go包初始化

huangapple go评论72阅读模式
英文:

Go Package Initialization

问题

Situation:

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

Question:

B实际上是被初始化了3次还是只有1次?

英文:

Situation:

A Go package A is composed of 3 .go files, and I use functions from another package B in each of these files. I have to import package B at the beginning of each file.

Question:

Is package B actually initialized 3 times or only 1 time?

答案1

得分: 38

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

详细回答:引用相关的规范部分 - 程序执行

> 没有导入的包通过为其所有的包级变量分配初始值,然后调用其源代码中定义的具有以下名称和签名的任何包级函数进行初始化:
>
> 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,这些goroutine可以与初始化代码并发运行。然而,初始化始终按顺序进行init函数:在前一个init函数返回之前,不会启动下一个init函数。

英文:

Short answer: Initialization will be performed only once.

Long answer: Quoting the relevant specification section - Program execution:

> A package with no imports is initialized by assigning initial values to all its package-level variables and then calling any package-level function with the name and signature of
>
> func init()
>
> defined in its source. A package-scope or file-scope identifier with name init may only be declared to be a function with this signature. Multiple such functions may be defined, even within a single source file; they execute in unspecified order.
>
> Within a package, package-level variables are initialized, and constant values are determined, according to order of reference: if the initializer of A depends on B, A will be set after B. Dependency analysis does not depend on the actual values of the items being initialized, only on their appearance in the source. A depends on B if the value of A contains a mention of B, contains a value whose initializer mentions B, or mentions a function that mentions B, recursively. It is an error if such dependencies form a cycle. If two items are not interdependent, they will be initialized in the order they appear in the source, possibly in multiple files, as presented to the compiler. Since the dependency analysis is done per package, it can produce unspecified results if A's initializer calls a function defined in another package that refers to B.
>
> An init function cannot be referred to from anywhere in a program. In particular, init cannot be called explicitly, nor can a pointer to init be assigned to a function variable.
>
> If a package has imports, the imported packages are initialized before initializing the package itself. If multiple packages import a package P, P will be initialized only once.
>
> The importing of packages, by construction, guarantees that there can be no cyclic dependencies in initialization.
>
> A complete program is created by linking a single, unimported package called the main package with all the packages it imports, transitively. The main package must have package name main and declare a function main that takes no arguments and returns no value.
>
> func main() { … }
>
> Program execution begins by initializing the main package and then invoking the function main. When the function main returns, the program exits. It does not wait for other (non-main) goroutines to complete.
>
> Package initialization—variable initialization and the invocation of init functions—happens in a single goroutine, sequentially, one package at a time. An init function may launch other goroutines, which can run concurrently with the initialization code. However, initialization always sequences the init functions: it will not start the next init until the previous one has returned.

huangapple
  • 本文由 发表于 2013年7月19日 04:25:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/17733220.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定