go入口文件与包初始化(待再次回顾)

入口函数mian.mian

Go 语言中有一个特殊的函数:main 包中的 main 函数,也就是 main.main,它是所有 Go 可执行程序的用户层执行逻辑的入口函数。Go 程序在用户层面的执行逻辑,会在这个函数内按照它的调用顺序展开。

可执行程序的 main 包必须定义 main 函数,否则 Go 编译器会报错。在启动了多个 Goroutine(Go 语言的轻量级用户线程,后面我们会详细讲解)的 Go 应用中,main.main 函数将在 Go 应用的主 Goroutine 中执行。

无参数,无返回值

除了 main 包外,其他包也可以拥有自己的名为 main 的函数或方法。但按照 Go 的可见性规则(小写字母开头的标识符为非导出标识符),非 main 包中自定义的 main 函数仅限于包内使用。

man.main是用户层逻辑的入口函数,但它却不一定是用户层第一个被执行的函数。

init 函数:Go 包的初始化函数

init 函数也是一个无参数无返回值的函数

Go 程序中我们不能手工显式地调用 init,否则就会收到编译错误。

Go 包可以拥有不止一个 init 函数,每个组成 Go 包的 Go 源文件中,也可以定义多个 init 函数。在初始化 Go 包时,Go 会按照一定的次序,逐一、顺序地调用这个包的 init 函数。一般来说,先传递给 Go 编译器的源文件中的 init 函数,会先被执行;而同一个源文件中的多个 init 函数,会按声明顺序依次执行。

Go 包的初始化次序

Go 包是程序逻辑封装的基本单元,每个包都可以理解为是一个“自治”的、封装良好的、对外部暴露有限接口的基本单元。一个 Go 程序就是由一组包组成的,程序的初始化就是这些包的初始化。每个 Go 包还会有自己的依赖包、常量、变量、init 函数(其中 main 包有 main 函数)等。

go包初始化次序,demo流程图

 

 通过代码示例验证go程序启动后流程

prog-init-order
├── go.mod
├── main.go
├── pkg1
│   └── pkg1.go
├── pkg2
│   └── pkg2.go
└── pkg3
    └── pkg3.go

如果pkg1 包和 pkg2 包都依赖 pkg3 包,但根据 Go 语言规范,一个被多个包依赖的包仅会初始化一次,因此这里的 pkg3 包仅会被初始化了一次。

Go 运行时是按照“pkg3 -> pkg1 -> pkg2 -> main”的顺序,来对 Go 程序的各个包进行初始化的,而在包内,则是以“常量 -> 变量 -> init 函数”的顺序进行初始化。此外,main 包的两个 init 函数,会按照在源文件 main.go 中的出现次序进行调用。

Go包初始化次序总结

  • 依赖包按“深度优先”的次序进行初始化;
  • 每个包内按以“常量 -> 变量 -> init 函数”的顺序进行初始化;
  • 包内的多个 init 函数按出现次序进行自动调用。

init函数的用途

一:重置包级变量值

init 函数就好比 Go 包真正投入使用之前唯一的“质检员”,负责对包内部以及暴露到外部的包级数据(主要是包级变量)的初始状态进行检查。在 Go 标准库中,我们能发现很多 init 函数被用于检查包级变量的初始状态的例子,标准库 flag 包对 init 函数的使用就是其中的一个,这里我们简单来分析一下。

flag 包定义了一个导出的包级变量 CommandLine,如果用户没有通过 flag.NewFlagSet 创建新的代表命令行标志集合的实例,那么 CommandLine 就会作为 flag 包各种导出函数背后,默认的代表命令行标志集合的实例。

二:实现对包级变量的复杂初始化

三:在init 函数中实现“注册模式”

 

参考地址:https://time.geekbang.org/column/article/432021

没太搞明白,随后再复习理解

 

posted on 2022-07-11 23:36  爱吃柠檬不加糖  阅读(94)  评论(0编辑  收藏  举报

导航