Golang Go语言中的 init 函数

Golang Go语言中的 init 函数

「阅读全文」

标识符 main 无所不在。每个 Go 程序的执行都是从 main 包中一个拥有相同名字的函数开始的。当这个 main 函数返回时,整个程序也退出了执行。init 函数也扮演着特定的角色,本文会描述它们的特性并介绍它们的使用方法。

init 函数是定义在包级别的,它被用于:

  • 初始化无法使用表达式初始化的变量
  • 检查和修复程序的状态
  • 注册
  • 执行一次性的运算
  • 以及其它

除了下面要介绍一些区别,你可以将任何在一般函数中有效的代码放在其中。

包的初始化

要使用一个引入的包,首先它需要被初始化。这是由 Golang 的运行系统来完成的,由以下几步(顺序很重要)组成:

  1. 初始化引入的包(递归释义)
  2. 计算并初始化赋值包级别的变量
  3. 执行包内的 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 是没有被申明的,所以无法被引用:

「阅读全文」


更多关于Golang Go语言中的 init 函数的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

我觉得标题中的译可以或者说应该用方括号,就是那种内部涂黑的,V2 好像会转化那种括号到这个: [,也不错

更多关于Golang Go语言中的 init 函数的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


单个文件多个 init 执行顺序是什么?同一 package 下,init 的执行顺序又是什么,

在Go语言中,init函数是一个特殊的函数,用于包的初始化。它有几个重要的特点和用途:

  1. 自动调用:每个包可以包含多个init函数,它们在程序开始执行时,在main函数之前自动被调用,且调用顺序是包依赖关系的顺序。

  2. 无参数和返回值init函数不能有任何参数,也不能有返回值。

  3. 全局变量初始化init函数通常用于设置包级变量的初始状态,或执行一些只需在程序启动时运行一次的设置操作。

  4. 执行顺序:在同一个包中,如果有多个init函数,它们会按照出现的顺序依次执行。不同包之间的init函数执行顺序则依据包依赖关系决定,即先初始化依赖的包。

  5. 不能显式调用init函数不能被其他函数调用,也不能被显式地声明为init之外的名称。

  6. 并发安全init函数的执行是串行的,即在一个包的多个init函数之间,或在包依赖链中的不同包之间,init函数的执行是顺序的,不会并发执行。

通过合理使用init函数,开发者可以在程序启动时自动执行必要的初始化操作,从而简化程序的主逻辑,保持代码的整洁和模块化。然而,也应当避免在init函数中执行复杂或耗时的操作,以免影响程序的启动性能。

回到顶部