2.14 Go之包的概念
包的基本概念
-
Go使用包组织源代码。
-
包(
package
)是多个Go
源码的集合,是一种高级的代码复用方案。 -
任何源代码文件必须属于某个包,同时源码文件的第一行有效代码必须是
package pacakgeName
语句,通过该语句声明自己所在的包。
包名的特点:
目录树的组织形式,一般包的名称就是其源文件所在目录的名称。Go
语言没有强制要求包名必须和其所在的目录名同名,但还是建议包名和所在目录同名
在GOPATH/src/a/b/
下定义一个包c
。在包c
的源码中只需声明为package c
,而不是声明为package a/b/c
,但是在导入c
包时,需要带上路径,例如import "a/b/c"
。
包的习惯用法
-
包名一般是小写的,使用一个简短且有意义的名称。
-
包名一般要和所在的目录同名,也可以不同,包名中不能包含
-
等特殊符号。 -
包一般使用域名作为目录名称,这样能保证包名的唯一性,比如
GitHub
项目的包一般会放到GOPATH/src/github.com/userName/projectName
目录下。 -
包名为
main
的包为应用程序的入口包,编译不包含main
包的源码文件时不会得到可执行文件。 -
一个文件夹下的所有源码文件只能属于同一个包,同样属于同一个包的源码文件不能放在多个文件夹下。
包的导入
语法:
import "包的路径"
注意:
-
import 导入语句通常放在源码文件开头包声明语句的下面;
-
导入的包名需要使用双引号包裹起来;
-
包名是从
GOPATH/src/
后开始计算的,使用/
进行路径分隔。
包导入的方法:
单行导入
多行导入
单行导入:
import "包 1 的路径"
import "包 2 的路径"
多行导入:
import (
"包 1 的路径"
"包 2 的路径"
)
包的导入路径
全路径导入
相对路径导入
全路径导入:
import "lab/a"
相对路径导入:
import "../a"
包的引用格式
-
标准引用格式
-
自定义别名引用格式
-
省略引用格式
-
匿名引用格式
标准引用格式
import "fmt"
包方法调用:
package main
import "fmt"
func main() {
fmt.Println("Lucifer")
}
自定义别名引用格式
导入包时为包设置别名:
import F "fmt"
包方法调用:
package main
import F "fmt"
func main() {
F.Println("Lucifer")
}
省略引用格式
import ."fmt"
示例代码:
package main
import . "fmt"
func main() {
//不需要加前缀 fmt.
Println("Lucifer")
}
匿名引用格式
特点: 在引用某个包时,如果只是希望执行包初始化的init
函数,而不使用包内部的数据,使用匿名引用格式
-
匿名导入的包与其他方式导入的包一样都会被编译到可执行文件中。
-
使用标准格式引用包,但是代码中却没有使用包,编译器会报错。如果包中有
init
初始化函数,则通过import _ "包的路径"
这种方式引用包,仅执行包的初始化函数,即使包没有init
初始化函数,也不会引发编译器报错。
import _ "fmt"
示例代码:
package main
import (
_ "database/sql"
"fmt"
)
func main() {
fmt.Println("C语言中文网")
}
包加载
包加载过程:
包的加载过程实际就是一个递归的过程:
包初始化特点:
-
包初始化程序从
main
函数引用的包开始,逐级查找包的引用,直到找到没有引用其他包的包,最终生成一个包引用的有向无环图。 -
Go
编译器会将有向无环图转换为一棵树,然后从树的叶子节点开始逐层向上对包进行初始化。 -
单个包的初始化过程如上图所示,先初始化常量,然后是全局变量,最后执行包的
init
函数。