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~

相关推荐
雾沉川3 小时前
Visual C++运行库合集 v105.0 安装教程
开发语言·c++·dll
许雪里4 小时前
Agent 记忆架构设计:原理 × 业界三大范式 × XXL-AI 落地实践
后端·llm·agent
niucloud-admin4 小时前
NIUCLOUD LITE AI开发文档—模块开发:支付管理
开发语言
dear_bi_MyOnly5 小时前
栈和队列:从原理到应用全解析
c语言·开发语言·c++·学习·分类
Want5955 小时前
Python大雪纷飞①
开发语言·python·数学建模
yujunl5 小时前
重写了一个BOM查询的脚本
开发语言
事圆则缓5 小时前
Kotlin 集合与序列:给页面一份清楚的数据
开发语言·windows·kotlin
事圆则缓5 小时前
Kotlin 异步与并发:从一次搜索请求走到状态流
android·开发语言·kotlin
黄鹂鸟科技6 小时前
进销存系统设计要点:从采购计划、库存监控到成本核算
后端·物联网·系统架构
从小白到软工6 小时前
4-3 项目-学生成绩管理系统(上)
c语言·开发语言·数据结构·经验分享·ai编程