「读书笔记」在 init 函数中检查包级变量的初始状态

192 阅读2分钟

函数与方法

20 在 init 函数中检查包级变量的初始状态

init 函数是一个无参数、无返回值的函数,如果一个包定义了 init 函数,Go 运行时会负责在该包初始化时调用它的 init 函数。在 Go 程序中我们不能显式调用 init,否则会在编译期间报错。

一个 Go 包可以拥有多个 init 函数,每个组成 Go 包的 Go 源文件中可以定义多个 init 函数。在初始化 Go 包时,Go 运行时会按照一定的次序逐一调用该包的 init 函数。Go 运行时不会并发调用 init 函数,它会等待一个 init 函数执行完毕并返回后再执行下一个 init 函数,且每个 init 函数在整个 Go 程序生命周期内仅会被执行一次。因此,init 函数极其适合做一些包级数据的初始化及初始状态的检查工作。

一般来说,先被传递给 Go 编译器的源文件中的 init 函数先被执行,同一个源文件中的多个 init 函数按声明顺序依次执行。但 Go 语言的惯例告诉我们:不要依赖 init 函数的执行次序

程序初始化顺序:

  • Go 运行时根据包导入的顺序去初始化 main 包的每一个依赖包;
  • Go 运行时遵循“深度优先”原则去初始化依赖包;
  • 在依赖包内,按照 常量->变量->init函数 的顺序进行初始化;
  • 最后初始化 main 包本身。

可以看出,init 函数适合做包级数据的初始化及初始状态检查工作的前提是:init 函数的执行顺位排在其所在包的包级变量之后

使用 init 函数检查包级变量的初始状态:

  • 重置包级变量值
  • 对包级变量进行初始化,保证其后续可用
  • init 函数中的注册模式:降低了 Go 包对外的直接暴露,尤其是包级变量的暴露,避免了外部通过包级变量对包状态的改动。从 database/sql 的角度来看,实质是一种工厂设计模式的实现,sql.Open 函数就是该模式中的工厂方法,它根据外部传入的驱动名称生产出不同类别的数据库实例句柄。
  • init 函数中检查失败的处理方法:保证其所在包在被正式使用之前的初始状态是有效的。一般建议直接调用 panic 或者通过 log.Fatal 等函数记录异常日志,然后让程序快速退出。

关注我

掘金:XQGang

Github: XQ-Gang

参考

《Go 语言精进之路:从新手到高手的编程思想、方法和技巧》——白明