package
Go语言是使用包来组织源代码的,包(package)是多个 Go 源码的集合,是一种高级的代码复用方案。Go语言中为我们提供了很多内置包,如 fmt、os、io 等。任何源代码文件必须属于某个包,同时源码文件的第一行有效代码必须是package pacakgeName
语句,通过该语句声明自己所在的包。
Go语言的包借助了目录树的组织形式,一般包的名称就是其源文件所在目录的名称,虽然Go语言没有强制要求包名必须和其所在的目录名同名,但还是建议包名和所在目录同名,这样结构更清晰。
1.1、包的基本使用
导入包的语法:
import "包的路径" // 双引号
导入包路径规则:
Go 程序首先在 GOROOT/src
目录中寻找包目录,如果没有找到,则会去 GOPATH/src
目录中继续寻找。比如 fmt
包是位于 GOROOT/src
目录的 Go 语言标准库中的一部分,它将会从该目录中导入。
目录结构
db
包
package db
import "fmt"
func HandleMySQL() {
fmt.Println("操作MySQL数据库")
}
package db
import "fmt"
func HandleRedis() {
fmt.Println("操作redis数据库")
}
api包
package api
import "fmt"
import "mysite/db"
func RestfulAPI() {
db.HandleMySQL()
fmt.Println("RestfulAPI:MySQL数据接口")
}
package api
import "fmt"
import "mysite/db"
func RpcAPI() {
db.HandleRedis()
fmt.Println("RpcAPI:redis数据接口")
}
main
包
package main
import "mysite/api"
func main() {
// db.HandleMySQL()
// db.HandleRedis()
api.RestfulAPI()
api.RpcAPI()
}
1、包名一般是小写的,见名知意,包名中不能包含-
等特殊符号。
2、包名规范上要和所在的目录同名,也可以不同。比如package api
改为package newApi
,代码改动为
package main
import newApi "mysite/api"
func main() {
newApi.RestfulAPI()
newApi.RpcAPI()
}
3、包名为 main 的包为应用程序的入口包,编译不包含 main 包的源码文件时不会得到可执行文件。
4、一个文件夹下的所有源码文件只能属于同一个包,同样属于同一个包的源码文件不能放在多个文件夹下。
5、一个包下的不同文件不能含有同名函数。
6、如果想在一个包中引用另外一个包里的标识符(如变量、常量、类型、函数等)时,该标识符必须是对外可见的(public),在Go语言中只需要将标识符的首字母大写就可以让标识符对外可见了。
7、环境变量GO111MODULE=off
: go env -w GO111MODULE=off
8、将mysite
剪切到src
外的任何位置,都会导包失败。
1.2、包的导入格式
// 一次导入多个包
import (
"fmt"
"mysite/api"
)
// 设置包的别名
import F "fmt"
// 省略引用格式
import . "mysite/api"
RestfulAPI()
// 匿名导入 :在引用某个包时,如果只是希望执行包初始化的 init 函数,而不使用包内部的数据时,可以使用匿名引用格式
import _ "包名"
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
1.3、包的加载顺序
init()
函数会在每个包完成初始化后自动执行,并且执行优先级比main函数高。
init 函数通常被用来:
-
对变量进行初始化
-
检查/修复程序的状态
-
注册
-
运行一次计算
注意:
1、一个包可以有多个 init 函数,包加载时会执行全部的 init 函数,但并不能保证执行顺序,所以不建议在一个包中放入多个 init 函数,将需要初始化的逻辑放到一个 init 函数里面。
2、包不能出现环形引用的情况,比如包 a 引用了包 b,包 b 引用了包 c,如果包 c 又引用了包 a,则编译不能通过。
3、包的重复引用是允许的,比如包 a 引用了包 b 和包 c,包 b 和包 c 都引用了包 d。这种场景相当于重复引用了 d,这种情况是允许的,并且 Go 编译器保证包 d 的 init 函数 只会执行一次
。
4、init()
函数没有参数也没有返回值。 init()
函数在程序运行时自动被调用执行,不能在代码中主动调用它。