go 程序初始化

本文代码地址:go 程序初始化

一、package 的作用

1.1 包是什么

包是 golang 的最小组织单元 , 每个.go文件的第一行必须是package 包名(明确回答了我是谁的问题),一个目录下的所有.go文件必须属于同一个包

注意看我这个目录结构:

bash 复制代码
[vect@ubuntu-dev ~/golang/priciple/go_tour]$ tree
.
├── go.mod
├── main.go
├── package1
│   └── package1.go
├── package2
│   └── package2.go
└── utils
    └── utils.go

4 directories, 5 files

go_tour入口包,生成可执行文件

go_tour/package1 是普通库包,被 main 引用

go_tour/package2是普通库包,被 package1 引用

go_tour/utils 是工具包,被多个包引用

1.2 包 = 命名空间 + 访问控制

golang 复制代码
var Val1 = ...  // 大写开头 → 导出,其他包可用:package2.Val1
var val1 = ...  // 小写开头 → 私有,仅本包内可用

golang 所有的设计都是如此,不论是变量、函数、方法等,只要首字母大写,就表明导出,可以被其他包使用

二、init 函数的作用

2.1 init 是什么

init() 是 golang 的自动初始化函数,不需要手动调用,golang 运行时自动执行,有如下特点:

  • 无参无返回值
  • 不能被其它函数调用(main也不行)
  • 一个包内可以有多个init(),按照源文件字母序->同一文件内从上到下一次执行的顺序

例如,我的main.go中有两个init()

golang 复制代码
func init() { fmt.Println("init func1 in main") }  // 先执行
func init() { fmt.Println("init func2 in main") }  // 后执行

2.2 init 的用途

  • 注册驱动
  • 初始化全局配置
  • 校验环境变量

这些动作只需要做一次,所以,不管包被导入多少次,包内的init()只会执行一次

三、golang 程序初始化全流程

初始化遵循依赖图,按照被依赖者优先原则:

从叶子节点(无依赖的utils 和 package2)开始初始化,逐层往上

每个包内又分两步:

  1. 包内变量初始化,按照声明顺序
  2. 执行 init()函数

按照详细的顺序来:

text 复制代码
程序启动
  │
  ├─► 导入 main,发现 import "go_tour/package1"
  │     │
  │     ├─► 导入 package1,发现 import "go_tour/package2" 和 "go_tour/utils"
  │     │     │
  │     │     ├─► 导入 package2,发现 import "go_tour/utils"
  │     │     │     │
  │     │     │     ├─► 导入 utils(无依赖,最底层)
  │     │     │     │     └─► utils 包初始化完毕
  │     │     │     │
  │     │     │     ├─► 初始化 package2 包级变量:Val1, Val2
  │     │     │     └─► 执行 package2 的 init()
  │     │     │
  │     │     ├─► utils 已初始化,复用(不重复执行)
  │     │     ├─► 初始化 package1 包级变量:V1, V2
  │     │     └─► 执行 package1 的 init()
  │     │
  │     ├─► 初始化 main 包级变量:MainVal1, MainVal2
  │     └─► 执行 main 的 init()
  │
  └─► 执行 main()

注意以下关键要点:

规则 说明
每个包只初始化一次 utils 被 package1 和 package2 同时引用,但 TraceLog 输出只出现 6 次(而非更多),因为 utils 的变量和 init 只跑一遍
依赖先行 被 import 的包一定先于 import 它的包初始化
变量先于 init 同一包内,包级变量初始化 → init() → 这才轮到被其他包引用
禁止循环依赖 如果 A import B 且 B import A,编译直接报错
_ 导入也会触发初始化 import _ "pkg" 不引用任何导出符号,但仍会执行该包的变量初始化和 init()

done~

相关推荐
mldong38 分钟前
C# 开发者也有自己的轻量工作流引擎了:NuGet 装包,5 分钟跑通一条审批流
后端·c#·.net
kruptos2 小时前
分布式系统怎么“选主“?Raft 共识一次讲清
开发语言·分布式·php·共识算法
吴声子夜歌2 小时前
ApacheCommons——commons-cli(命令行参数解析)
java·开发语言·apache
爱学堂IT分享3 小时前
鹤翔老师pmp项目管理培训认证考试课 (直播录播题库送学时证明)【共58课时】-51CTO学堂
后端
benchmark_cc3 小时前
REST API 和 Python SDK 应该怎么选?量化交易数据接口选型实战
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
王的宝库3 小时前
Go 项目结构:从单文件到标准工程布局
开发语言·后端·golang
Tairitsu_H3 小时前
[C++] 深入理解红黑树:封装set与map
开发语言·c++·set·map·红黑树·模拟实现
泡海椒3 小时前
JQuick-Curl 性能分析:并发场景下的性能表现与调优,第三方接口调用不只要快写也要稳跑
java·开发语言·okhttp
小智老师PMP3 小时前
2026深度解析|PMP第八版与NPDP核心侧重点本质区别(管理类证书怎么选)
开发语言·分布式·算法·职场和发展·产品经理
花酒锄作田4 小时前
Go - Gin中使用sessions
golang