我试图找到一个关于init()函数在Go中的作用的精确解释。我读了Effective Go说的话,但我不确定我是否完全理解了它说的话。我不太确定的句子是:

finally的意思是最后:init是在包中所有变量声明都计算了它们的初始化式之后调用的,并且只有在所有导入的包都初始化之后才会计算这些初始化式。

包中所有变量声明对其初始化式求值意味着什么?这是否意味着如果你在一个包和它的文件中声明“全局”变量,init()将不会运行,直到所有的它被评估,然后它将运行所有的init函数,然后main()当。/main_file_name运行?

我还读了Mark Summerfield的书:

如果一个包有一个或多个init()函数,它们会在主包的main()函数被调用之前自动执行。

在我的理解中,init()只在您打算运行main()时才相关,对吗?如果有人更清楚地理解init(),请随意纠正我


当前回答

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.

其他回答

init func首先运行,然后是main。它用于在程序运行之前先设置一些东西,例如:

访问模板, 使用所有核心运行程序, 检查Goos和arch等…

还有一些建议:

只能有一个main()函数,但可以有很多init()函数。 你不需要显式地调用init()或main(),它们会自动调用。 Init()和main()不接受任何参数,也不返回任何东西。 Init()在main()之前运行。 如果你有很多init(),它们会按照声明的顺序运行。

在一个包中混合init函数执行顺序:

Const和变量定义的文件init()函数执行 初始化函数按文件名asc执行

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之前运行。

看这张照片。:)

导入——> const——> var——> init()

如果一个包导入了其他包,则首先初始化导入的包。 当前包的常量初始化。 然后初始化当前包的变量。 最后,调用当前包的init()函数。

一个包可以有多个init函数(可以在单个文件中,也可以分布在多个文件中),并且按照它们呈现给编译器的顺序调用它们。

一个包只能被初始化一次,即使它是从多个包中导入的。