基本概念
- 包是函数和数据的集合 将有相关特性的函数和数据放在统一的文件/目录 中进行管理
- 每个包都可以作为独立的单元进行维护 并提供给其他项目进行使用
一、声明
- Go 源文件都需要在开头使用 package 声明所在哪个包
- 包名使用简短的小写字母,常与所在目录名保持一致,一个包中可以由多个 Go 源文件,但 必须使用相同包名
工作目录结构说明:
- bin: 用于放置发布的二进制程序
- pkg: 用于放置发布的库文件
- src: 用于放置源代码
二、导入&调用
1. 声明两个包,路径分别为 gpkgname/pkg01 和 gpkgname/pkg02
gv/src/gpkgname/pkg01/module.go
package pkg01
var Name string = "pgk01"
gv/src/gpkgname/pkg02/module.go
package pkg02
var Name string = "pgk02"
2. 创建gv/src/gpkgmain/main.go 调用gpkgname/pkg01和gpkgname/pkg02
gv/src/gpkgmain/main.go
package main
import (
"fmt"
"gpkgname/pkg01"
"gpkgname/pkg02"
)
func main(){
fmt.Println("gpkgmain")
fmt.Println(pkg01.Name)
fmt.Println(pkg02.Name)
}
目录结构是这样的
[root@happy gv]# tree /Users/wangfei/docker/go/chapter08/
/Users/wangfei/docker/go/chapter08/
└── gv
├── bin
└── src
├── gpkgmain
│ └── main.go
└── gpkgname
├── pkg01
│ └── module.go
└── pkg02
└── module.go
3.将chapter08/gv目录添加到GOPATH环境变量中
[root@happy gv]# GOPATH=/Users/wangfei/docker/go/chapter08/gv
[root@happy gv]# echo $GOPATH
/Users/wangfei/docker/go/chapter08/gv
4.编译二进制文件
- 命令:go build gpkgmain
- 说明:编译路径 gpkgmain 下的包,main 包,则在当前目录产生以 pkgmain 命名的 二进制程序
[root@happy gv]# go build gpkgmain
[root@happy gv]# ll
total 2032
drwxr-xr-x 2 root root 4096 Nov 15 10:36 bin
-rwxr-xr-x 1 root root 2068379 Nov 15 10:36 gpkgmain
drwxr-xr-x 3 root root 4096 Nov 15 10:37 pkg
drwxr-xr-x 4 root root 4096 Nov 15 10:33 src
目录结构是这样的
tree /Users/wangfei/docker/go/chapter08/
/Users/wangfei/docker/go/chapter08/
└── gv
├── gpkgmain
5.运行二进制文件
[root@happy gv]# ./gpkgmain
gpkgmain
pgk01
pgk02
6.编译并发布二进制文件
- 命令:go install gpkgmain
- 说明:编译并发布路径 gv/src/gpkgmain下的main 包,会将编译后的二进制文件 pkgmain拷贝到 gv/bin 目录
[root@happy gv]# go install gpkgmain
[root@happy gv]# ls /Users/wangfei/docker/go/chapter08/gv/bin/
gpkgmain
7. 编译发布库文件
- 命令:go install gpkgname/pkg01
- 说明:编译并发布路径 gpkgname/pkg01 下的包,非 main 包,将编译的以包名 命名的库文件拷贝到 pkg/GOOS_GOARCH 目录下, (linux是pkg/linux_amd64 GOOS_GOARCH会根据平台类型改变)
[root@happy gv]# go install gpkgname/pkg01
[root@happy gv]# go install gpkgname/pkg02
生成后的路径是这样的
[root@happy gv]# tree /Users/wangfei/docker/go/chapter08/gv
/Users/wangfei/docker/go/chapter08/gv
├── pkg
│ └── linux_amd64
│ └── gpkgname
│ ├── pkg01.a
│ └── pkg02.a
8.编译发布所有二进制和库文件
- 命令:go install ./...
- 说明:编译并发布当前路径下的所有二进制程序和库文件
- 注意:Go 语言不允许交叉导入包
[root@happy gv]# go install ./...
三、导入形式
1. 绝对路径导入
- 在 GOPATH 目录中查找包
import "fmt"
import "gpkgname/pkg01"
2. 相对路径导入
- 在当前文件所在的目录查找
import "./gpkgname/pkg02"
3. 点导入
- 在调用点 导入包中的成员时可以直接使用成员名称进行调用(省略包名)
import . "fmt"
func main(){
Println("Hello World!")
}
4.别名导入
- 当导入不同路径的相同包名时,用别名对导入的包进行重命名,避免冲突
package main
import f "fmt"
func main(){
f.Println("Hello World!")
}
5. 下划线导入
- Go 不允许包导入但未使用, 在某些情况下需要初始化包,使用空白符作为别名进行导入,从而使得包中的初始化函数可以执行
package main
import _ "fmt"
四、成员可见性 和 函数
1.成员可见性
- Go 语言使用名称首字母大小写来判断对象(常量、变量、函数、类型、结构体、方法等)的访问权限
- 首字母大写标识包外可见(公开的) 否则仅包内可访问(内部的)
2.main 包与 main 函数
- main包 用于声明 告知编译器将包编译为二进制可执行文件
- main包中的main函数 是程序的入口,无返回值,无参数
3.init 函数
- init 函数是初始化包使用,无返回值,无参数
- init 函数在 import 包时自动会被调用(const->var->init)
pkg01/module.go
package pkg01
import "fmt"
// Public
var Name string = "pkg01"
// private
var version string = "v2.0"
// init
func init(){
fmt.Println("version is :", version)
}
main.go
package main
import (
"fmt"
"gpkgname/pkg01"
"gpkgname/pkg02"
)
func init(){
fmt.Println("main init")
}
func main(){
fmt.Println("gpkgmain")
fmt.Println(pkg01.Name) //调用pkg01包中的成员Name
fmt.Println(pkg02.Name) //调用pkg02包中的成员Name
}
五、Go包管理
- Go1.11 版本供 Go modules 机制对包进行管理,同时保留 GOPATH 和 vendor 机制, 临时环境变量 GO111MODULE 进行控制
- GO111MODULE的三个值
- GO111MODULE为off, 构建项目始终在GOPATH和vendor目录搜索目标程序依赖包
- GO111MODULE为on, 始终使用Gomodules机制, 在GOPATH/pkg/mod目录搜索目标程序依赖包
- GO111MODULE为auto(默认)
GOPATH+vendor 机制
1.vendor
- 将项目依赖包拷贝到项目下的 vendor 目录,在编译时使用项目下 vendor 目录中的包进行编译
- 解决问题:
- 依赖外部包过多,在使用第三方包时需要使用go get进行下载
- 第三方包在go get下载后 不能保证开发和编译时版本的兼容性
2.搜索顺序
- 在当前包下的vendor目录查找
- 向上级目录查找,直到GOPATH/src/vendor目录
- 在GOPATH目录查找
- 在GOROOT目录查找
3.第三方包
- 可以借助 go get 工具下载和安装第三方包及其依赖
- 需要安装与第三方包匹配的代码 管理工具,比如 git、svn 等
GOPATH=/Users/wangfei/docker/go/chapter08/gv
go get -x github.com/astaxie/beego
常用参数:
- -d:仅下载依赖包
- -u:更新包并安装
- -x:打印执行的命令
- -v:打印构建的包
- -insecure:允许使用http协议下载包
第三方包查找地址:
Go modules 机制
优势:
- 不用设置GOPATH,代码可任意放置
- 自动下载依赖管理
- 版本控制
- 不允许使用相对导入
- replace机制
初始化模块
- 命令: go mod init modname
当前模块下的包 对于当前模块下的包导入时需要使用 modname+packagename
第三方包
- 在使用 go mod tidy、go build、go test、go list 命令会自动将第三方依赖包写入到 go.mod 文件中
- 同时下载第三方依赖包到 GOPATH/pkg/mod/cache 目录,并在当前模块目录生成一个构建状态跟踪文件 go.sum
- 文件中记录当前 module 所有的顶层和间接依赖, 以及这些依赖的校验和
常用命令
- go mod tidy:整理依赖模块(添加新增的,删除未使用的)
- go mod vendor: 将依赖模块拷贝到模块中的 vendor 目录
- go build: 编译当前模块
- go build ./...: 编译当前目录下的所有模块
- gobuild-mod=vendor:使用当前模块下的vendor目录中的包进行编译
- go mod download: 仅下载第三方模块
- go mod grapha: 打印所有第三方模块
- go list -m -json all:显示所有模块信息
- go mod edit: 修改 go.mod 文件 -require=pakcage@version - replace=old_package@version=new_package@version 可以使用-replace 功能将包替换为本地包,实现相对导入
六、标准包
Go 供了大量标准包,可查看:golang.google.cn/pkg/
godoc 工具
- 使用 godoc 命令可以在本地启动 golang 网站,用于本地查看帮助手册
- godoc --http=localhost:8888
- go list std:查看所有标准包
- go doc packagename:查看包的帮助信息
- go doc packagename.element:查看包内成员帮助信息