init() 函数是什么时候执行的?

答:init()是再main()函数执行前

一句话总结: import –> const –> var –> init() –> main()

如果有多个init就要分情况

单个源文件的 init 执行顺序

结论: 同一个源文件的 init 函数执行顺序与其定义顺序一致,从上到下。

package main

func init() {
    println("init a")
}

func init() {
    println("init b")
}

func init() {
    println("init c")
}

func main() {
    println("main")
}
$ go run main.go
init a
init b
init c
main

单个包的 init 执行顺序

结论: 同一个包中不同源文件 init 函数的执行顺序,是根据文件名的字典序来确定。

// a.go
package main

func init() {
    println("init a")
}

// b.go
package main

func init() {
    println("init b")
}

// c.go
package main

func init() {
    println("init c")
}

// main.go
package main

func init() {
    println("init main")
}

func main() {
    println("main")
}
$ go build && ./main
init a
init b
init c
init main
main

main 包导入多个包时 init 执行顺序-不存在依赖

结论: 对于不同的包,如果不相互依赖的话,按照 main 包中导入顺序调用包的 init 函数,最后再调用 main 包的 init 函数。

// a 包
// a.go
package a

func init() {
    println("init a")
}

// b 包
// b.go
package b

func init() {
    println("init b")
}

// c 包
// c.go
package c

func init() {
    println("init c")
}

// main 包
// main.go
package main

import (
    _ "main/a"
    _ "main/b"
    _ "main/c"
)

func init() {
    println("init main")
}

func main() {
    println("main")
}
$ go build && ./main
init a
init b
init c
init main
main

main 包导入多个包时 init 执行顺序-存在依赖

结论: 如果 package 存在依赖,不同包的 init 函数按照包导入的依赖关系决定执行顺序。 调用顺序为最后被依赖的最先被初始化,如导入顺序 main > a > b > c,则初始化顺序为 c > b > a > main,依次执行对应的 init 方法

// a 包
// a.go
package a

import _ "main/b"

func init() {
    println("init a")
}

// b 包
// b.go
package b

import _ "main/c"

func init() {
    println("init b")
}

// c 包
// c.go
package c

func init() {
    println("init c")
}

// main 包
// main.go
package main

import (
    _ "main/a"
)

func init() {
    println("init main")
}

func main() {
    println("main")
}
$ go build && ./main
init c
init b
init a
init main
main

包级变量初始化与 init 函数执行顺序

结论:如果包存在包级变量,则先于包的 init 函数完成初始化。

// a 包
// a.go
package a

import _ "main/b"

var A = func() string {
    println("init var A")
    return "A"
}()

func init() {
    println("init a")
}

// b 包
// b.go
package b

import _ "main/c"

var B = func() string {
    println("init var B")
    return "B"
}()

func init() {
    println("init b")
}

// c 包
// c.go
package c

var C = func() string {
    println("init var C")
    return "C"
}()

func init() {
    println("init c")
}

// main 包
// main.go
package main

import (
    _ "main/a"
)

var m = func() string {
    println("init var m")
    return "m"
}()

func init() {
    println("init main")
}

func main() {
    println("main")
}
$ go build && ./main
init var C
init c
init var B
init b
init var A
init a
init var m
init main
main

参考资料: