go允许定义多个init(),多个init()会涉及到执行先后的问题,本文将详细讲解这个问题.
概述
init()
一般用来做一些初始化工作, go允许定义多个init()
,根据init()
重复场景不同,可以分为
- 同文件 单文件中定义多个
init()
- 同模块 同模块下不同文件中定义了多个
init()
- 子模块 本模块和子模块都包含
init()
- 跨模块 多个被引用模块中均含
init()
要点秘诀:
- 涉及引用时,先加载的先执行
- 同一文件中,先定义的先执行
同文件
一个文件中出现多个init()
时,执行顺序是从上往下按照定义顺序执行的,先定义的执行.
package main
import "fmt"
func main(){
}
func init(){
fmt.Println("first...")
}
func init(){
fmt.Println("second...")
}
func init(){
fmt.Println("third...")
}
执行结果
first...
second...
third...
调整一下定义顺序
package main
import "fmt"
func main() {
}
func init() {
fmt.Println("third...")
}
func init() {
fmt.Println("second...")
}
func init() {
fmt.Println("first...")
}
执行结果
third...
second...
first...
同模块
同模块下定义多个init()
,执行顺序是根据文件加载顺序来执行的,文件加载顺序就是文件名的字符串排序.
代码测试一下,新建一个模块websit
,目录结构如下
- |---src
- |---websit
- |---acfun.go
- |---bilibili.go
- |---websit
- |---main.go
main.go内容如下
package main
import (
_ "website"
)
func main() {
}
acfun.go内容如下
package website
import "fmt"
func init() {
fmt.Println("AcFun弹幕视频网 - 认真你就输啦 (・ω・)ノ- ( ...")
}
bilibili.go内容如下
``go
package website
import "fmt"
func init(){
fmt.Println("哔哩哔哩 (゜-゜)つロ 干杯~-bilibili")
}
运行结果为
```text
AcFun弹幕视频网 - 认真你就输啦 (・ω・)ノ- ( ...
哔哩哔哩 (゜-゜)つロ 干杯~-bilibili
文件名排序,acfun.go
在bilibili.go
之前,所以acfun.go
会先被加载,文件中的init()
会先被执行.
如果acfun.go
中定义了多个init()
,执行顺序和同文件一样.
子模块
与同模块一样,先被加载的先执行.
修改上述demo文件路径,增加个子模块login
.
- |---src
- |---websit
- |---login
- |----login.go
- |---acfun.go
- |---bilibili.go
- |---login
- |---websit
- |---main.go
login.go
内容如下
package login
import "fmt"
func init(){
fmt.Println("login...")
}
修改acfun.go
package website
import (
"fmt"
_ "website/login"
)
func init() {
fmt.Println("AcFun弹幕视频网 - 认真你就输啦 (・ω・)ノ- ( ...")
}
执行结果:
login...
AcFun弹幕视频网 - 认真你就输啦 (・ω・)ノ- ( ...
哔哩哔哩 (゜-゜)つロ 干杯~-bilibili
ps:go模块加载详解请查阅另外一篇文章.
多模块
- 同子模块一样,哪个模块先被
import
就先被加载. - 这个模块如果有子模块,会先加载子模块
- 如果子模块中有多个文件,根据文件名排序决定文件加载顺序
- 一个文件被加载时,如果定义多个
init()
,先定义的先执行.