标识符 main
无所不在。每个 Go 程序的执行都是从 main
包中一个拥有相同名字的函数开始的。当这个 main
函数返回时,整个程序也退出了执行。init
函数也扮演着特定的角色,本文会描述它们的特性并介绍它们的使用方法。
init
函数是定义在包级别的,它被用于:
除了下面要介绍一些区别,你可以将任何在一般函数中有效的代码放在其中。
要使用一个引入的包,首先它需要被初始化。这是由 Golang 的运行系统来完成的,由以下几步(顺序很重要)组成:
init
方法包的初始化过程只会被执行一次,即使它被多次引用
Go 语言的包可以包含许多文件。那么在这些包和文件中,变量的初始化和 init
函数的执行顺序是怎样的呢?首先,初始化依赖机制会起作用(详情可以查看“Go 中的初始化依赖”)。当依赖工作完成后,必须决定先初始化 a.go 文件中的变量还是 z.go 文件中的变量。这依赖于文件在编译器中出现的顺序。如果 z.go 先被提交给构建系统,那么它的变量就会先于 a.go 中的变量初始化。init
方法的调用也遵守相同的顺序。语言规格定义中建议总是采用相同的顺序,并且将包中的文件按单词拼写顺序传入:
为了保证初始化行为可稳定复现,构建系统应该倾向于将同一个包中的多个文件按文件名的单词拼写顺序传递给编译器。
不过对于移植性较差的程序来说也可以使用特别的顺序。我们用下面的例子看看这些是如何一起工作的:
sandbox.go
package main
import "fmt"
var _ int64 = s()
func init() {
fmt.Println("init in sandbox.go")
}
func s() int64 {
fmt.Println("calling s() in sandbox.go")
return 1
}
func main() {
fmt.Println("main")
}
a.go
package main
import "fmt"
var _ int64 = a()
func init() {
fmt.Println("init in a.go")
}
func a() int64 {
fmt.Println("calling a() in a.go")
return 2
}
z.go
package main
import "fmt"
var _ int64 = z()
func init() {
fmt.Println("init in z.go")
}
func z() int64 {
fmt.Println("calling z() in z.go")
return 3
}
程序输出:
calling a() in a.go
calling s() in sandbox.go
calling z() in z.go
init in a.go
init in sandbox.go
init in z.go
main
init
函数不接受任何参数,也没有返回值。于 main
相比,标识符 init
是没有被申明的,所以无法被引用:
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.