前言
Go语言有超过100个的标准包,可以通过以下命令获取标准包
go list std
也可以通过http://godoc.org检索包。
模块化设计成每个包可以被其它的不同项目共享和重用,在项目范围内统一的分发和复用。每个包一般都定义了一个不同的名字空间,防止命名冲突。还通过控制包内名字的可见性和是否导出来实现封装性,还可以强制用户通过某些特定函数来访问和更新内部变量,这样可以保证内部变量的一致性和并发时的互斥约束。
当我们修改了一个源文件,我们必须重新编译该源文件对应的包和所有依赖该包的其他包。可以并发编译,有向无环图遍历+标记状态,目标文件同时还记录了包的依赖关系可以进行剪枝。
1. package声明
每个Go语言源文件的开头都必须有包声明语句
package main
1.1 特殊包
- main包对应一个可执行程序,main包提示go build构建命令,这个包编译完之后必须调用连接器生成一个可执行程序。
- 测试外部扩展包(
_test
为后缀)由go test命令独立编译,避免测试代码中的循环导入依赖,e.g. package memo_test - 版本包 导入路径后追加版本号信息,e.g. gopkg.in/yaml.v2
2. import路径
为了避免冲突,所有非标准库包的导入路径建议以所在组织的互联网域名为前缀;而且这样也有利于包的检索。例如,下面的import语句导入了Go团队维护的官方HTML解析器和一个流行的第三方维护的MySQL驱动。gofmt和goimports工具有助于自动导入、排序和格式排版。
import (
"fmt" // 标准包
"math/rand"
"golang.org/x/net/html" // 官方扩展包
"github.com/go-sql-driver/mysql" // github第三方包
)
默认的包名就是包导入路径名的最后一段,因此即使两个包的导入路径不同,它们依然可能有一个相同的包名。例如math/rand包和crypto/rand包,那么导入声明必须至少为一个同名包指定一个别名以避免冲突。这叫做导入包的重命名。
import (
"crypto/rand"
mrand "math/rand" // 别名
)
别名不仅仅只是为了解决名字冲突,也可以缩短笨重的包名,引用更方便。 每个导入声明语句都明确指定了当前包和被导入包之间的依赖关系。如果遇到包循环导入的情况,Go语言的构建工具将报告错误。
Go语言的执行过程,每次import会出发依赖包地常量变量初始化和init方法,import时递归下去,最终所有包初始化完成进入main包地main函数执行主流程。
2.1 匿名导入
如果只是导入一个包而并不使用导入的包将会导致一个编译错误。
有时候我们只是想利用导入包而产生的副作用:它会计算包级变量的初始化表达式和执行导入包的init初始化函数。这时候我们需要抑制“unused import”编译错误,我们可以用下划线_
来重命名导入的包。
import _ "image/png" // 副作用注册PNG 解码器
import (
"database/sql"
_ "github.com/lib/pq" // 第三方数据库驱动enable support for Postgres
_ "github.com/go-sql-driver/mysql" // enable support for MySQL
)
3.包命名规范
- 包名一般采用单数的形式。
- 要避免包名有其它的含义。
- 考虑包名和成员名两个部分如何很好地配合,如http.Get
4.工具
go工具 | 解释 |
---|---|
go env | Go语言工具涉及的所有环境变量的值 |
go get | 下载一个单一的包或者用
clone整个仓库
|
go build | 编译命令行参数指定的每个包。 如果包名是main,将调用链接器在当前目录创建一个可执行程序;以导入路径的最后一段作为可执行程序的名字。 如果没有指定参数,那么默认指定为当前目录对应的包
|
go install | 类似于build,只是会保存每个包的编译成果到$GOPATH/pkg |
go doc | 构建doc文档 所有导出成员注释 |
go list | 查询可用包的信息 |
go test | 运行Go语言程序中的测试代码 |