4.5 Eric Zhou Golang 2019-09-27
在Go中,预定义init()函数会触发执行init函数中的代码,使其在包的任何其他代码之前运行. 该代码将在import package后立即执行,并且可以在需要您的app以特定方式初始化, 例如,当您具有启动app的config或resource时. import package 使用init函数的副作用来设置和初始化一些包的状态. 这通常用于register一个包和另一个包,以确保程序正在考虑代码的正确性.
尽管这init()是一个有用的工具,但有时会使代码难以阅读,因为难以搞清楚的所有包中的init()函数的执行. 因此,对于刚接触Go的开发人员来说,了解此功能的各个方面非常重要, 以便他们在coding时可以确保init()以清晰易懂的方式执行.
import _ "github.com/jinzhu/gorm/dialects/sqlite"
,相当于注册driverimport _ "github.com/jinzhu/gorm/dialects/sqlite"
这种方式使用go get/mod 下载其他package为了使用导入的包,首先必须将其初始化. 初始化总是以单线程执行,并且按照包的依赖关系顺序执行.这通过Golang的运行时系统控制. 正如上图所示:
main.go
package main import "fmt" var _ int64=s() func init(){ fmt.Println("开始执行init函数") } func s() int64{ fmt.Println("开始初始化const/var") return 1 } func main(){ fmt.Println("开始执行main函数") }
执行go run main.go
代码输出结果
$ go run play.go 开始初始化const/var 开始执行init函数 开始执行main函数
即使包被导入多次,初始化只需要一次.如果是多层级的import package 安装上面图示顺序执行.
在Go中,有时希望导入软件包不是出于其内容,而是出于导入软件包时发生的副作用(Side Effects). 这通常意味着init()在导入的代码中有一条语句在其他任何代码之前执行, 从而使开发人员可以操纵其程序启动时的状态.这种技术被称为导入副作用(Side Effects).
导入副作用的一个常见用例是在代码中注册功能, 这使程序包知道程序需要使用代码的哪一部分. 在image封装中,例如,该image.Decode功能需要知道它正试图解码(其图像的格式jpg,png,gif等), 然后才能执行.您可以通过首先导入具有init()语句副作用(Side Effects)的特定程序来完成此操作.
假设您正尝试对一个.png文件执行image.Decode.代码段如下:
... func decode(reader io.Reader) image.Rectangle { m, _, err := image.Decode(reader) if err != nil { log.Fatal(err) } return m.Bounds() } ...
上面这对代码会被编译出来,不会报错.但是当我们decode png文件的时候程序将会报错.
要修复,我们需要先为image.Decode注册图片格式png.非常幸运的是image/png包init函数含一下声明.
image/png/reader.go
func init() { image.RegisterFormat("png", pngHeader, Decode, DecodeConfig) }
因此,如果我们import “image/png” 到我们上面的解码代码中,然后在image/png中的 image.RegisterFormat()
函数将最先执行. 最终代码如下:
... import _ "image/png" ... func decode(reader io.Reader) image.Rectangle { m, _, err := image.Decode(reader) if err != nil { log.Fatal(err) } return m.Bounds() }
这将设置状态并注册我们需要的png版本image.Decode(). 该注册将作为导入image/png包的副作用而执行.
您可能之前已经注意到空白标识符_(下划线)”image/png”. 这是必需的,因为Go不允许您导入程序中未使用的程序包. 通过包括空白标识符,导入本身的值将被丢弃,从而仅导入的副作用得以解决. 这意味着,即使我们从不image/png在代码中调用该包,也可以出于副作用而将其导入.
了解何时需要导入软件包的副作用(import _ “your/package”)非常重要. 如果没有正确注册,则程序可能会编译成功,但在运行时无法正常运行. 标准库中的软件包将在其文档中声明需要这种类型的导入. 如果编写的程序包需要导入以产生副作用, 则还应确保记录了init()正在使用的语句,以便导入程序包的用户将能够正确使用它.
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句