08.init函数与import导包

1.init函数

1.1.init函数详解

init()函数会在每个包完成初始化后自动执行,并且执行优先级比main函数高。init函数通常被用来:

  • 对变量进行初始化
  • 检查/修复程序的状态
  • 注册
  • 运行一次计算

1.2.包的初始化

为了使用导入的包,首先必须将其初始化。初始化总是以单线程执行,并且按照包的依赖关系顺序执行。这通过Golang的运行时系统控制,如上图所示:

  1. 初始化导入的包(递归导入)
  2. 对包块中声明的变量进行计算和分配初始值
  3. 执行包中的init函数

1.3.示例代码

// 代码结构
├── initFunc.go
├── initFunc_test.go
├── lib1
│   └── lib1.go
└── lib2
    └── lib2.go

// lib1.go
package lib1

import "fmt"

// init 函数
func init() {
    fmt.Println("lib1==>>init()....")
}

// run
func Run1() {
    fmt.Println("lib1====>>>run().....")
}

// lib2.go
package lib2

import "fmt"

// init 函数
func init() {
    fmt.Println("lib2==>>init()....")
}

// run
func Run2() {
    fmt.Println("lib2====>>>run().....")
}

// initFunc.go
package chapter05

import (
    "fmt"

    "e.coding.net/ywang/Go/gdev/hour/chapter05/lib1"
    "e.coding.net/ywang/Go/gdev/hour/chapter05/lib2"
)

func init() {
    fmt.Println("main====>>>> init().....")
}

// main
func Run() {
    lib1.Run1()
    lib2.Run2()
}

// initFunc_test.go
package chapter05

import "testing"

func TestRun(t *testing.T) {
    Run()
}

// 执行结果
lib1==>>init()....
lib2==>>init()....
main====>>>> init().....
=== RUN   TestRun
lib1====>>>run().....
lib2====>>>run().....
--- PASS: TestRun (0.00s)
PASS
ok      e.coding.net/ywang/Go/gdev/hour/chapter05   0.223s

1.4.说明

  • 函数名首字母大写,表示函数可以对外使用,首字母小写表示,只可以包内引用

1.5.每个源文件中可以包含多个init函数

// 修改 lib1.go、lib2.go和 initFunc.go的代码
//lib1.go
package lib1

import "fmt"

// init 函数
func init() {
    fmt.Println("lib1==>>init1()....")
}

func init() {
    fmt.Println("lib1==>>init2()....")
}

// run
func Run1() {
    fmt.Println("lib1====>>>run().....")
}

// lib2.go
package lib2

import "fmt"

// init 函数
func init() {
    fmt.Println("lib2==>>init1()....")
}

func init() {
    fmt.Println("lib2==>>init2()....")
}

// run
func Run2() {
    fmt.Println("lib2====>>>run().....")
}


// initFunc.go
package chapter05

import (
    "fmt"

    "e.coding.net/ywang/Go/gdev/hour/chapter05/lib1"
    "e.coding.net/ywang/Go/gdev/hour/chapter05/lib2"
)

func init() {
    fmt.Println("main====>>>> init1().....")
}

func init() {
    fmt.Println("main====>>>> init2().....")
}

// main
func Run() {
    lib1.Run1()
    lib2.Run2()
}

// 执行结果
lib1==>>init1()....
lib1==>>init2()....
lib2==>>init1()....
lib2==>>init2()....
main====>>>> init1().....
main====>>>> init2().....
=== RUN   TestRun
lib1====>>>run().....
lib2====>>>run().....
--- PASS: TestRun (0.00s)
PASS
ok      e.coding.net/ywang/Go/gdev/hour/chapter05   0.538s

1.6.总结

  • init函数不需要传入参数,也不会返回任何值
  • init 没有被声明,不能被引用
  • 每个源文件可以包含多个init函数

2.import导包

2.1.使用_对包进行匿名引用

// initFunc.go
package chapter05

import (
    "fmt"

    _ "e.coding.net/ywang/Go/gdev/hour/chapter05/lib1"
    "e.coding.net/ywang/Go/gdev/hour/chapter05/lib2"
)

func init() {
    fmt.Println("main====>>>> init1().....")
}

func init() {
    fmt.Println("main====>>>> init2().....")
}

// main
func Run() {
    //lib1.Run1()
    lib2.Run2()
}

// 执行结果
lib1==>>init1()....
lib1==>>init2()....
lib2==>>init1()....
lib2==>>init2()....
main====>>>> init1().....
main====>>>> init2().....
=== RUN   TestRun
lib2====>>>run().....
--- PASS: TestRun (0.00s)
PASS
ok      

说明

  • _ "e.coding.net/ywang/Go/gdev/hour/chapter05/lib1" 匿名引用lib1
  • 执行结果中看到,lib1下的init函数正常执行
  • 无法使用当前包的方式,但是会执行当前包内部的init方法。

2.2.使用别名导入包

// initFunc.go
package chapter05

import (
    "fmt"

    _ "e.coding.net/ywang/Go/gdev/hour/chapter05/lib1"      // 匿名导入包
    mylib2 "e.coding.net/ywang/Go/gdev/hour/chapter05/lib2" // 别名导入包
)

func init() {
    fmt.Println("main====>>>> init1().....")
}

func init() {
    fmt.Println("main====>>>> init2().....")
}

// main
func Run() {
    //lib1.Run1()
    // 别名导入包
    mylib2.Run2()
    // lib2.Run2()
}
// 执行结果
lib1==>>init1()....
lib1==>>init2()....
lib2==>>init1()....
lib2==>>init2()....
main====>>>> init1().....
main====>>>> init2().....
=== RUN   TestRun
lib2====>>>run().....
--- PASS: TestRun (0.00s)
PASS
ok      

2.3.使用.方式导入包

// initFunc.go
package chapter05

import (
    "fmt"

    _ "e.coding.net/ywang/Go/gdev/hour/chapter05/lib1"      // 匿名导入包
    // mylib2 "e.coding.net/ywang/Go/gdev/hour/chapter05/lib2" // 别名导入包
    . "e.coding.net/ywang/Go/gdev/hour/chapter05/lib2" // 使用.的方式导入包
)

func init() {
    fmt.Println("main====>>>> init1().....")
}

func init() {
    fmt.Println("main====>>>> init2().....")
}

// main
func Run() {
    //lib1.Run1()
    // 别名导入包
    // mylib2.Run2()
    // lib2.Run2()
    // 使用 . 方式导入包,直接调用函数
    Run2()

}
// 执行结果
lib1==>>init1()....
lib1==>>init2()....
lib2==>>init1()....
lib2==>>init2()....
main====>>>> init1().....
main====>>>> init2().....
=== RUN   TestRun
lib2====>>>run().....
--- PASS: TestRun (0.00s)
PASS
ok      

说明

  • .的方式,不推荐使用,但Go是支持的;原因是多个`
  • 包内所有方法都可以直接通过API来调用,不需要包名.API方式使用。

2.4.总结

posted @ 2021-10-08 10:03  可可逗豆  阅读(188)  评论(0)    收藏  举报