包package

  1. Go使用包来组织源代码

  2. 内置包源码位于$GOROOT/src

  3. 定义包:

    1. 包名一般是小写的,使用一个简短且有意义的名称

    2. 包名一般要和所在的目录同名,也可以不同,包名中不能包含- 等特殊符号

    3. 一个文件夹下的所有源码文件只能属于同一个包,同样属于同一个包的源码文件不能放在多个文件夹下

    4. 包的定义不包含路径,比如定义包:package myp,不会定义package ppkg/myp

    5. 包名为 main 的包为应用程序的入口包,编译不包含 main 包的源码文件时不会得到可执行文件

    6. 包一般使用域名作为目录名称,这样能保证包名的唯一性,比如 GitHub 项目的包一般会放到GOPATH/src/github.com/userName/projectName 目录下

  4. 导入包:

    1. 导入包需要带上路径import ppkg/myp

    2. 包名称是从$GOPATH/src/下面进行计算的,使用/分割,import ppkg/myp的路径实际为$GOPAT/src/ppkg/myp

导入包

// 单行导入
import "包 1. 入门 的路径"
import "包 2 的路径"

// 多行导入
import (
    "包 1. 入门 的路径"
    "包 2 的路径"
)

// 全路径导入
// 全路径是指GOROOT/src/或GOPATH/src/后面包的存放路径
import "lab/test"
import "database/sql/driver"
import "database/sql

// 相对路径导入
import "../a"

引用包

导入包后,需要对包内的成员进行引用,有以下几种引用方式

  • 标准引用:

    package main
    import "fmt" // 不使用包会报错
    func main() {
    	fmt.Println("hello") // 使用包名.成员名称
    }
  • 自定义别名引用,当包名称有冲突时使用

    package main
    import F "fmt" // 不使用包会报错
    func main() {
    	F.Println("hello") // 使用包别名.成员名称
    }
  • 省略引用格式,将包内的内容合并到当前源文件中

    package main
    import . "fmt" // 不使用包会报错
    func main() {
    	Println("hello") // 不需要任何前缀,直接使用
    }
  • 匿名引用格式,如果只是希望执行包初始化的 init 函数,而不使用包内部的数据时,可以使用匿名引用格式,即使不使用包也不会报错

    package main
    import (
    	_ "database/sql" // 即使不使用包,也不会报错
    	"fmt"
    )
    func main() {
    	fmt.Println("C语言中文网")
    }
    

init函数

  • 一个包可以有多个 init 函数,包加载时会执行全部的 init 函数,但并不能保证执行顺序,所以不建议在一个包中放入多个 init 函数,将需要初始化的逻辑放到一个 init 函数里面。

  • 包不能出现环形引用的情况,比如包 a 引用了包 b,包 b 引用了包 c,如果包 c 又引用了包 a,则编译不能通过。

  • 包的重复引用是允许的,比如包 a 引用了包 b 和包 c,包 b 和包 c 都引用了包 d。这种场景相当于重复引用了 d,这种情况是允许的,并且 Go 编译器保证包 d 的 init 函数只会执行一次。

  • main包中的init函数将会先于main函数运行。

    package main
    
    import "fmt"
    
    func init() {
    	fmt.Println("init")
    }
    func main() {
    	fmt.Println("Hello")
    }
    // 运行结果
    // init
    // Hello

包加载

Go语言包的初始化有如下特点:

  • 包初始化程序从 main 函数引用的包开始,逐级查找包的引用,直到找到没有引用其他包的包,最终生成一个包引用的有向无环图。

  • Go 编译器会将有向无环图转换为一棵树,然后从树的叶子节点开始逐层向上对包进行初始化。

  • 单个包的初始化过程如上图所示,先初始化常量,然后是全局变量,最后执行包的 init 函数。

导出标识符

标识符包含变量、常量、方法等,只需要将其首字母大写即可导出:

package mypkg

var myVar = 100
const MyConst = "hello"
type MyStruct struct {
}

如果结构体或者函数中的值也想导出,也将标识符首字母大写即可:

type MyStruct struct {
    // 包外可以访问的字段
    ExportedField int
    // 仅限包内访问的字段
    privateField int
}

type MyInterface interface {
    // 包外可以访问的方法
    ExportedMethod()
    // 仅限包内访问的方法
    privateMethod()
}

最后更新于