内容简介:转载:大家都知道golang里的main函数是程序的入口函数,main函数返回后,程序也就结束了。golang还有另外一个特殊的函数init函数,先于main函数执行,实现包级别的一些初始化操作,今天我们就深入介绍下init的特性。golang程序初始化先于main函数执行,由runtime进行初始化,初始化顺序如下:
Golang的init函数
转载: https://zhuanlan.zhihu.com/p/34211611
大家都知道golang里的main函数是程序的入口函数,main函数返回后,程序也就结束了。golang还有另外一个特殊的函数init函数,先于main函数执行,实现包级别的一些初始化操作,今天我们就深入介绍下init的特性。
init函数的主要作用:
- 初始化不能采用初始化表达式初始化的变量。
- 程序运行前的注册。
- 实现sync.Once功能。
- 其他
init函数的主要特点:
- init函数先于main函数自动执行,不能被其他函数调用;
- init函数没有输入参数、返回值;
- 每个包可以有多个init函数;
- 包的每个源文件也可以有多个init函数 ,这点比较特殊;
- 同一个包的init执行顺序,golang没有明确定义,编程时要注意程序不要依赖这个执行顺序。
- 不同包的init函数按照包导入的依赖关系决定执行顺序。
golang程序初始化
golang程序初始化先于main函数执行,由runtime进行初始化,初始化顺序如下:
- 初始化导入的包(包的初始化顺序并不是按导入顺序(“从上到下”)执行的,runtime需要解析包依赖关系,没有依赖的包最先初始化,与变量初始化依赖关系类似,参见 golang变量的初始化 );
- 初始化包作用域的变量(该作用域的变量的初始化也并非按照“从上到下、从左到右”的顺序,runtime解析变量依赖关系,没有依赖的变量最先初始化,参见 golang变量的初始化 );
- 执行包的init函数;
示例1:
main.go
package main import ( "fmt" ) var T int64 = a() func init() { fmt.Println("init in main.go ") } func a() int64 { fmt.Println("calling a()") return 2 } func main() { fmt.Println("calling main") }
输出:
calling a() init in main.go calling main
初始化顺序: 变量初始化->init()->main()
示例2:
pack.go
package pack import ( "fmt" "test_util" ) var Pack int = 6 func init() { a := test_util.Util fmt.Println("init pack ", a) }
test_util.go
package test_util import "fmt" var Util int = 5 func init() { fmt.Println("init test_util") }
main.go
package main import ( "fmt" "pack" "test_util" ) func main() { fmt.Println(pack.Pack) fmt.Println(test_util.Util) }
输出:
init test_util init pack 5 6 5
由于pack包的初始化依赖test_util,因此运行时先初始化test_util再初始化pack包;
示例3:
sandbox.go
package main import "fmt" var _ int64 = s() func init() { fmt.Println("init in sandbox.go") } func s() int64 { fmt.Println("calling s() in sandbox.go") return 1 } func main() { fmt.Println("main") }
a.go
package main import "fmt" var _ int64 = a() func init() { fmt.Println("init in a.go") } func a() int64 { fmt.Println("calling a() in a.go") return 2 }
z.go
package main import "fmt" var _ int64 = z() func init() { fmt.Println("init in z.go") } func z() int64 { fmt.Println("calling z() in z.go") return 3 }
输出:
calling a() in a.go calling s() in sandbox.go calling z() in z.go init in a.go init in sandbox.go init in z.go main
同一个包不同源文件的init函数执行顺序,golang spec没做说明,以上述程序输出来看,执行顺序是源文件名称的字典序。
示例4:
package main import "fmt" func init() { fmt.Println("init") } func main() { init() }
init函数不可以被调用,上面代码会提示:undefined: init
示例5:
package main import "fmt" func init() { fmt.Println("init 1") } func init() { fmt.Println("init 2") } func main() { fmt.Println("main") }
输出:
init 1 init 2 main
init函数比较特殊,可以在包里被多次定义。
示例6:
var initArg [20]int func init() { initArg[0] = 10 for i := 1; i < len(initArg); i++ { initArg[i] = initArg[i-1] * 2 } }
init函数的主要用途:初始化不能使用初始化表达式初始化的变量
示例7:
import _ "net/http/pprof"
golang对没有使用的导入包会编译报错,但是有时我们只想调用该包的init函数,不使用包导出的变量或者方法,这时就采用上面的导入方案。
执行上述导入后,init函数会启动一个异步协程采集该进程实例的资源占用情况,并以http服务接口方式提供给用户查询
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Python 拓展之特殊函数(lambda 函数,map 函数,filter 函数,reduce 函数)
- Python 函数调用&定义函数&函数参数
- python基础教程:函数,函数,函数,重要的事说三遍
- C++函数中那些不可以被声明为虚函数的函数
- 017.Python函数匿名函数
- 纯函数:函数式编程入门
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Rework
Jason Fried、David Heinemeier Hansson / Crown Business / 2010-3-9 / USD 22.00
"Jason Fried and David Hansson follow their own advice in REWORK, laying bare the surprising philosophies at the core of 37signals' success and inspiring us to put them into practice. There's no jarg......一起来看看 《Rework》 这本书的介绍吧!