package main import "fmt" func main() { fmt.Printf("调用了main()函数,此时name=%+v \n", name) } func init() { name = "张三" fmt.Printf("调用了init()函数-1,此时name=%+v \n", name) } func init() { name = "李四" fmt.Printf("调用了init()函数-2,此时name=%+v \n", name) } func init() { name = "王五" fmt.Printf("调用了init()函数-3,此时name=%+v \n", name) } var name string //========== 输出过程·开始 ==========// // 调用了init()函数-1,此时name=张三 // 调用了init()函数-2,此时name=李四 // 调用了init()函数-3,此时name=王五 // 调用了main()函数,此时name=王五 //========== 输出过程·结束 ==========// //========== 总结 ==========// // 1、init()函数和main()函数一样都是有特定意义的保留函数,它的作用是完成一些初始化工作,任意一个.go文件都可以定义init()函数,并 // 且在一个.go文件里可以定义多个init()函数而不报redeclared错误。 // 2、init()函数会比main()函数先调用,如果一个.go文件里定义了常量和全局变量,并且定义了init()函数和main()函数,则执行顺序如下: // 定义常量 → 定义全局变量 → 调用init()函数 → 调用main()函数 注:一个.go文件里如有多个init()函数则按定义顺序逐个调用 // 3、init()函数不能被手动调用,如果在其它函数里手动调用init()函数编译时会报“undefined: init”错误。 // 4、Go编译器会从main包开始,根据包的import情况构建出整个项目的包引用关系(树形结构),然后根据引用关系由下往上对包进行编译。由 // 于是根据包引用关系编译的原因,如果代码中存在init()函数依赖就很容易出问题,例如a.go需要使用b.go的全局变量VarB,而VarB是b.go在 // init()函数里初始化的,也就是a.go依赖b.go的init()函数,但是由于包引用关系,a.go获取VarB时b.go的init()函数还未执行,这样程序就 // 会出问题。在大型系统中,由于包的引用关系复杂,为了避免出现init()函数依赖问题,定义了init()函数的.go文件应该自行判断是否已经执 // 行过init()函数,例如定义一个全局变量isInit(bool类型,默认为false),在init()函数里改变其值为true,这样就可以根据isInit的值判 // 断是否已经执行过init()函数,如果还未执行过init()函数就手动执行初始化操作。
Copyright © 2024 码农人生. All Rights Reserved