一、什么是init方法?

init 是 Go 语言中的特殊函数,无需手动调用,由运行时自动执行。每个 .go 文件可以包含多个 init 函数。init方法没有参数和返回值。

示例代码如下:

func init() {

    // 初始化逻辑
}

init 函数在 main() 函数之前执行。当包被导入时,系统会自动调用所有 init 函数,其调用顺序为:先执行依赖包(被导入的包)的 init 函数,再执行当前包的 init 函数,最后执行 main() 函数。

二、init方法特性

1)执行顺序规则‌‌

(1)同一个文件多个init方法执行顺序

同一文件内的 init 函数则按照代码编写顺序执行,代码示例如下:

var config string

func init() {
    config = "config1"
    fmt.Println("init 1:", config)
}

func init() {
    fmt.Println("init 2: additional setup")
}

func main() {
    fmt.Println("main:", config)
}

执行结果如下:

(2)同一个包内执行顺序

同一包内的文件会按照文件名进行字典序排序,并按此顺序执行各文件中的 init 函数。如包内包括a.go和b.go两个文件,优先执行a.go中的init方法,在执行b.go中的init方法。

代码示例如下:

// a.go
package main

import "fmt"

func init() {
    fmt.Println("a.go init")
}

// b.go
package main

import "fmt"

func init() {
    fmt.Println("b.go init")
}

// main.go
package main

import "fmt"

func init() {
    fmt.Println("main init")
}

func main() {

    fmt.Println("main")
}

运行结果如下:

(3)跨包执行顺序

对于跨包依赖的情况,遵循"深度优先"原则,即最后被依赖的包会最先完成初始化。例如在 main → A → B → C 的依赖链中,初始化顺序为 C → B → A → main。

代码包结构如下:

代码示例如下:

// a.go
package A

import (
    "fmt"
    "te/src/B"
)

func init() {
    fmt.Println("a.go init")
}

func PrintA() {
    fmt.Println("print a")
    B.PrintB()
}


// b.go
package B

import (
    "fmt"
    "te/src/C"
)

func init() {
    fmt.Println("b.go init")
}

func PrintB() {
    fmt.Println("print b")
    C.PrintC()
}

// c.go
package C

import "fmt"

func init() {
    fmt.Println("c.go init")
}

func PrintC() {
    fmt.Println("print c")
}

// main.go
package main

import (
    "fmt"
    "te/src/A"
)

func init() {
    fmt.Println("main init")
}

func main() {

    fmt.Println("main")

    A.PrintA()
}

执行结果如下:

2)与变量初始化的关系‌

包级变量初始化优先于 init 执行。示例代码如下:

// 先执行
var config = initConfig()

func initConfig() string {
    fmt.Println("initConfig")
    return "initConfig"
}

// 后执行
func init() {
    config = "init"
    fmt.Println("init()", config)
}

func main() {
    fmt.Println(config)
}

运行结果如下:

三、init应用场景

场景 用途说明
全局变量初始化 复杂配置加载,如数据库连接池设置
驱动/插件注册 数据库驱动注册
副作用代码执行 日志系统初始化,如设设置日志级别和输出格式
确保初始化顺序 依赖资源预加载,如配置文件读取优先于服务启动

四、init使用注意事项

1)避免滥用:过度使用 init 函数会降低代码可读性,建议采用显式初始化方式。对于复杂逻辑,应封装为普通函数并在 main 中显式调用。

2)线程安全:所有 init 函数都在同一个 goroutine 中执行,因此无需加锁。

3)初始化方法应仅包含不会失败的操作 。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐