Go 语言包初始化顺序详解

在Go中,当程序启动时,包初始化过程遵循特定顺序:

1、当存在 import 包,会递归先初始化依赖包,依此再初始化第二个 import 包

Go 复制代码
package main

import (
	"fmt"
	_ "inittest/dao" // 导入 dao 包, 会先初始化该包的内容,再执行主函数单元的 init()
)

// 主函数单元 init
func init() {
	fmt.Println("主函数单元 init")
}

func main() {
    fmt.Println("主函数单元执行 main 函数")
}

/* 执行结果:

dao 包下的 order 文件单元全局变量创建: OrderInfo
dao 包下的 order 文件单元 init

主函数单元 init
主函数单元执行 main 函数
*/

2、单个包内的初始化顺序为先初始化变量,再执行 init 函数。

Go 复制代码
package main

import (
	"fmt"
)

type Conf struct {
}

// 新建全局变量,会优先于 init() 函数初始化
var conf = NewConfig()  

func NewConfig() *Conf {
	fmt.Println("")
	fmt.Println("主函数单元全局变量创建: conf")
	return &Conf{}
}

// 主函数单元 init
func init() {
	fmt.Println("主函数单元 init")
}

func main() {
	fmt.Println("主函数单元执行 main 函数")
	if conf == nil {
		fmt.Println("配置项为空")
		return
	}
}

/* 执行结果:

主函数单元全局变量创建: conf
主函数单元 init
主函数单元执行 main 函数
*/

特别注意:

当一个包存在多个文件时,go 的初始化规则是:

①先处理所有文件的包级别变量(按文件中的出现顺序,但文件间的顺序不确定)

②再执行所有文件的 init 函数(按文件名字母顺序)

以下为完整示例,其中一个包中含有多个文件,项目结构如下:

inittest/

├── main.go # 项目入口文件

├── go.mod # Go 模块依赖配置

├── dao/ # 数据访问层 (Data Access Object)

│ └── order.go # 订单相关数据操作

└── root/ # 根包/初始化包

├── db.go # 数据库初始化配置

└── log.go # 日志初始化配置

执行结果:

包初始化顺序:

完整代码示例:

Go 复制代码
// 文件位置 inittest\main.go

package main

import (
	"fmt"
	"inittest/dao"    // 导入 dao 包
	_ "inittest/root" // 导入 root 包, root 包下有多个文件单元, 会将所有文件单元的 import 包递归初始化,然后再将所有文件的变量初始化,最后将所有文件的 init 函数执行
)

type Conf struct {
}

// 新建全局变量
var conf = NewConfig()

func NewConfig() *Conf {
	fmt.Println("")
	fmt.Println("主函数单元全局变量创建: conf")
	return &Conf{}
}

// 主函数单元 init
func init() {
	fmt.Println("主函数单元 init")
}

func main() {
	fmt.Println("主函数单元执行 main 函数")
	if conf == nil {
		fmt.Println("配置项为空")
		return
	}
	if dao.OrderInfo != nil {
		fmt.Println("主函数单元获取 dao 包下的全局变量 OrderInfo 成功")
		return
	}
}
Go 复制代码
// 文件位置 inittest\root\log.go

package root

import "fmt"

type Logger struct {
}

// 新建全局变量
var Log = NewLogger()

func NewLogger() *Logger {
	fmt.Println("root 包下的 log 文件单元全局变量创建: Log")
	return &Logger{}
}

func init() {
	fmt.Println("root 包下的 log 文件单元 init")
}
Go 复制代码
// 文件位置 inittest\root\db.go
package root

import "fmt"

type DB struct {
}

// 新建全局变量
var Db = NewDB()

func NewDB() *DB {
	fmt.Println("root 包下的 db 文件单元全局变量创建: db")
	return &DB{}
}

func init() {
	fmt.Println("root 包下的 db 文件单元 init")
}
Go 复制代码
// 文件位置 inittest\dao\order.go

package dao

import "fmt"

type Order struct {
}

// 新建全局变量
var OrderInfo = NewOrder()

func NewOrder() *Order {
	fmt.Println("dao 包下的 order 文件单元全局变量创建: OrderInfo")
	return &Order{}
}

func init() {
	fmt.Println("dao 包下的 order 文件单元 init")
	fmt.Println("")
}
相关推荐
JWASX5 小时前
【Go】map 源码解析 - group
后端·golang·map·源码分析
联犀1 天前
纯 Go 的 CAD 开源库 go-cad:直接解析 DWG/DXF,现在也能导出 PDF
开发语言·golang·pdf
FungLeo1 天前
成为全栈·Go 后端篇·三轮代码审阅之后:把可读性和证据做成工程规则
golang·go·ast·静态检查·成为全栈·代码审阅
联犀1 天前
联犀 Go SIMD 实战:视频转码从 16.5ms 到 5.46ms
开发语言·golang·音视频
紧跟先前的步伐2 天前
Go AI Agent 实战 28|Agent 的预算、超时与停止条件
开发语言·人工智能·后端·ai·golang
利威尔xu2 天前
2026-11-05-Go内存管理面试
面试·golang
Zenova EdgeOS4 天前
Go 工业边缘错误处理实战:用 errors 构建可追溯错误链
开发语言·数据库·golang
JavaPub-rodert4 天前
从零搭建通用管理后台:ShiyuAdmin 的 Go、React 与 RBAC 实践
开发语言·react.js·golang
microrain4 天前
SagooIoT 的数据接入层只有四张表,却能接住三种外部数据
物联网·golang·数据建模·sagooiot
fly-iot4 天前
【FDE知识库】(4):企业知识库怎么选型,开源知识库分享几个,选择开源协议友好的版本,开发wiki-go项目
golang·开源·开源协议