我试图找到一个关于init()函数在Go中的作用的精确解释。我读了Effective Go说的话,但我不确定我是否完全理解了它说的话。我不太确定的句子是:
finally的意思是最后:init是在包中所有变量声明都计算了它们的初始化式之后调用的,并且只有在所有导入的包都初始化之后才会计算这些初始化式。
包中所有变量声明对其初始化式求值意味着什么?这是否意味着如果你在一个包和它的文件中声明“全局”变量,init()将不会运行,直到所有的它被评估,然后它将运行所有的init函数,然后main()当。/main_file_name运行?
我还读了Mark Summerfield的书:
如果一个包有一个或多个init()函数,它们会在主包的main()函数被调用之前自动执行。
在我的理解中,init()只在您打算运行main()时才相关,对吗?如果有人更清楚地理解init(),请随意纠正我
这里是另一个例子- https://play.golang.org/p/9P-LmSkUMKY
package main
import (
"fmt"
)
func callOut() int {
fmt.Println("Outside is beinge executed")
return 1
}
var test = callOut()
func init() {
fmt.Println("Init3 is being executed")
}
func init() {
fmt.Println("Init is being executed")
}
func init() {
fmt.Println("Init2 is being executed")
}
func main() {
fmt.Println("Do your thing !")
}
上面程序的输出
$ go run init/init.go
Outside is being executed
Init3 is being executed
Init is being executed
Init2 is being executed
Do your thing !
Init将在任何使用它的包的地方被调用(无论是空白导入还是导入),但只有一次。
这是一个包:
package demo
import (
"some/logs"
)
var count int
func init() {
logs.Debug(count)
}
// Do do
func Do() {
logs.Debug("dd")
}
任何包(主包或任何测试包)作为空白导入:
_ "printfcoder.com/we/models/demo"
或者使用it func导入它:
"printfcoder.com/we/models/demo"
func someFunc(){
demo.Do()
}
init将只记录一次日志0。
第一个使用它的包,它的init func将在包的init之前运行。所以:
A调用B B调用C,它们都有init func, C的init会在B之前运行,B在A之前运行。
是的,假设你有这个:
var WhatIsThe = AnswerToLife()
func AnswerToLife() int { // 1
return 42
}
func init() { // 2
WhatIsThe = 0
}
func main() { // 3
if WhatIsThe == 0 {
fmt.Println("It's all a lie.")
}
}
AnswerToLife()保证在调用init()之前运行,并且init()保证在调用main()之前运行。
请记住,init()总是被调用,无论是否有main,所以如果你导入一个包,它有init函数,它将被执行。
此外,每个包可以有多个init()函数;它们将按照它们在文件中出现的顺序执行(当然是在所有变量初始化之后)。如果它们跨越多个文件,它们将按照词法文件名的顺序执行(正如@benc指出的那样):
init()函数似乎是按词法文件名顺序执行的。Go规范说:“构建系统被鼓励以词法文件名的顺序将属于同一个包的多个文件呈现给编译器”。似乎go build是这样工作的。
许多内部Go包使用init()来初始化表等,例如https://github.com/golang/go/blob/883bc6/src/compress/bzip2/bzip2.go#L480
init()函数何时运行?
使用Go 1.16 (Q1 2021),您将准确地看到它运行的时间以及运行多长时间。
参见从CL(更改列表)254659提交7c58ef7,修复问题41378。
Runtime: implement GODEBUG=inittrace=1 support
Setting inittrace=1 causes the runtime to emit a single line to standard error for
each package with init work, summarizing the execution time and memory allocation.
The emitted debug information for init functions can be used to find bottlenecks
or regressions in Go startup performance.
Packages with no init function work (user defined or compiler generated) are omitted.
Tracing plugin inits is not supported as they can execute concurrently. This would
make the implementation of tracing more complex while adding support for a very rare
use case. Plugin inits can be traced separately by testing a main package importing
the plugins package imports explicitly.
$ GODEBUG=inittrace=1 go test
init internal/bytealg @0.008 ms, 0 ms clock, 0 bytes, 0 allocs
init runtime @0.059 ms, 0.026 ms clock, 0 bytes, 0 allocs
init math @0.19 ms, 0.001 ms clock, 0 bytes, 0 allocs
init errors @0.22 ms, 0.004 ms clock, 0 bytes, 0 allocs
init strconv @0.24 ms, 0.002 ms clock, 32 bytes, 2 allocs
init sync @0.28 ms, 0.003 ms clock, 16 bytes, 1 allocs
init unicode @0.44 ms, 0.11 ms clock, 23328 bytes, 24 allocs
...
Inspired by stapelberg@google.com who instrumented doInit
in a prototype to measure init times with GDB.