深入理解Go语言init方法的执行顺序

 更新时间:2025年09月18日 09:45:00   作者:liushen0528  
本文主要介绍了深入理解Go语言init方法的执行顺序,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

一、什么是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)初始化方法应仅包含不会失败的操作 。

到此这篇关于深入理解Go语言init方法的执行顺序的文章就介绍到这了,更多相关Go语言init执行顺序内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Golang导入包的几种方式(点,别名与下划线)

    Golang导入包的几种方式(点,别名与下划线)

    这篇文章主要介绍了Golang导入包的几种方式(点,别名与下划线),文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • go语言中函数与方法介绍

    go语言中函数与方法介绍

    这篇文章介绍了go语言中的函数与方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07
  • Golang设计模式之适配器模式介绍和代码示例

    Golang设计模式之适配器模式介绍和代码示例

    适配器是一种结构型设计模式, 它能使不兼容的对象能够相互合作,可担任两个对象间的封装器, 它会接收对于一个对象的调用, 并将其转换为另一个对象可识别的格式和接口,本文将通过代码示例详细给大家介绍Golang的适配器模式
    2023-06-06
  • Golang结构化日志包log/slog的使用详解

    Golang结构化日志包log/slog的使用详解

    官方提供的用于打印日志的包是标准库中的 log 包,该包虽然被广泛使用,但是缺点也很多,所以Go 1.21新增的 log/slog 完美解决了以上问题,下面我们就来看看log/slog包的使用吧
    2023-09-09
  • golang Gorm框架讲解

    golang Gorm框架讲解

    gorm是一个使用Go语言编写的ORM框架,这篇文章主要介绍了golang Gorm框架,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-12-12
  • Go语言变量与类型使用简明指南

    Go语言变量与类型使用简明指南

    Go语言是静态编程语言,在Go语言中数据类型用于声明函数和变量,这篇文章主要介绍了Go语言变量与类型使用的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-09-09
  • go语言实现sqrt的方法

    go语言实现sqrt的方法

    这篇文章主要介绍了go语言实现sqrt的方法,实例分析了Go语言实现计算平方根的技巧,需要的朋友可以参考下
    2015-03-03
  • Golang技巧之重试机制详解

    Golang技巧之重试机制详解

    重试机制是一种在程序执行过程中出现错误后重新尝试执行程序的一种机制,可以减少程序运行过程中出现的错误,从而提高程序的可靠性,本文就来讲讲Golang中是如何实现重试机制的吧
    2023-05-05
  • go语言生成随机数和随机字符串的实现方法

    go语言生成随机数和随机字符串的实现方法

    随机数在很多时候都可以用到,尤其是登录时,本文就详细的介绍一下go语言生成随机数和随机字符串的实现方法,具有一定的参考价值,感兴趣的可以了解一下
    2021-12-12
  • Golang中context包使用场景和示例详解

    Golang中context包使用场景和示例详解

    这篇文章结合示例代码介绍了context包的几种使用场景,文中有详细的代码示例,对学习或工作有一定的帮助,需要的朋友可以参考下
    2023-05-05

最新评论