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~

相关推荐
牡丹雅忻112 分钟前
AES 加密模式演进:从 ECB、CBC 到 GCM 的 C# 深度实践
java·开发语言·c#
连续讨伐17 分钟前
php小结
开发语言·php
进击的程序猿~27 分钟前
Go 并发底层原理面试学习指南
开发语言·面试·golang
Python私教31 分钟前
Django 6.1 RC1 实测:FETCH_PEERS 两条 SQL 解决 N+1,select_related 还需要吗?
后端·python·django
脚踏实地皮皮晨32 分钟前
002002002_DepandencyObject类2
开发语言·windows·算法·c#·visual studio
大侠在此在在此39 分钟前
教你用最简单的数学自底向上地高效学习SQL注入
后端
Python私教1 小时前
Django 6.0 自带 Tasks 到底能不能替代 Celery?跑完 3 组后台任务后我有答案了
后端·python·django
练习时长一年1 小时前
@SneakyThrows注解
开发语言
我的xiaodoujiao1 小时前
快速学习Python基础知识详细图文教程14--模块
开发语言·python·学习·测试工具
NoteStream1 小时前
【c语言基础】C语言常见概念
c语言·开发语言·编辑器