包结构
工作空间
依照规范,工作空间(workspace)由src,bin,pkg三个目录组成。通常需要将空间路径添加到GOPATH环境变量列表中,以便相关工具能正常工作。
在工作空间里,包括子包在内的所有源码文件都包村在src目录下。至于bin,pkg两个目录,其主要影响go install/get命令,它们会将编译结果(可执行文件或静态库)安装到这两个目录下,已实现增量编译。
环境变量
编译器等相关工具按GOPATH设置的路径搜索目标。也就是在导入目标库是,排在表前面的路径比当前工作空间优先级更高。go get 默认将下载的第三方包保存到列表中第一个工作空间。
环境变量GOROOT用于指示工具链和标准库的存放位置。在生成工具链时,相关路径就已经嵌入到可执行文件内,故无须额外设置。
除了通过设置GOROOT环境变量覆盖内部路径外,还可移动目录(改名,符号链接等)。
至于GOBIN,则是强制代替工作空间的bin目录,作为go install 目标保存路径。这可避免将所有工作空间的bin路径添加到PATH环境变量中。
导入包
使用标准库或第三方包前,要import导入,参数是工作空间以src为起始的绝对路径。编译器从标准库开始搜索,然后依次搜索GOPATH列表中的各个工作空间。
import "net/http" // 实际路径 mac /usr/loacl/go/src/net/http
出了使用默认包名外,还可以使用别名,以解决同名冲突。
import osx "github.com/apple/osx/lib"
import nix "github.com/linux/lib"
import导入参数时路径,而非包名。尽管将包名和目录名保持一致,但不是强制规定。
未使用的导入(不包括初始化方式)会被编译器视为错误。
相对路径
除了工作空间和绝对路径外,部分工具还支持相对路径。可在非工作空间目录下,直接运行,编译一些测试代码。
自定义路径
即便将代码托管在GitHub,依然希望使用自定义域名定义下载和导入路径。方法很简单,在web服务器对应路径返回中包含“go-import”
组织结构
包(package)由一个或多个保存在同一目录下(不含子目录)的源码文件组成。包的用途类似命名空间(namespace),是成员作用域和访问权限的边界。
包名与目录名并无关系,不要求保持一致。
包名通常使用单数形式。源码文件必须使用UTF-8格式,否则会导致编译出错。
同一目录下所有源码文件必须使用相同的包名称。因导入时使用绝对路径,所以在搜索路径下,包必须有唯一路径,但无须是唯一名称。
另有几个被保留,有特殊含义的包名称:
- main: 可执行入口
- all : 标准库以及GOPATH中能找到的所有包
- std,cmd: 标准库及工具链
- documentation : 存储文档信息,无法导入
权限
所有成员在包内均可访问,无论是否在同一源码文件中,但只有名称首字母大写的可导出成员,在包外可视。
该规则使用适用全局变量,全局常亮,类型,结构字段,函数,方法等。
可以通过指针转换等方法绕开此限制。
初始化
包内每个源码文件都可定义一到多个初始化函数,但编译器不保证执行次序。
实际上,所有这些初始化函数(包括标准库和导入的第三方包)都有编译器自动生成的一个包装函数进行调用,因此可保证在单一线程上执行,且仅执行一次。
初始化函数之间不应该有逻辑关联,最好仅处理当前文件的初始化操作。
编译器首先确保完成所有全局变量初始化,然后才开始执行初始化函数。直到这些全部结束后,运行时才正式进入main.main入口函数。
如果在多个初始化函数中引用全局变量,那么最好在变量定义处直接赋值。因无法保证执行次序,所有任何初始化函数中的赋值都有可能“延迟无效。”
内部包
在进行代码重构是,会将一些内部模块陆续分离出来,以独立包形式维护。
希望这些包导出成员仅在特定范围内访问,而不是向所有用户公开。
内部报机制相当于增加了新的访问控制权限:所有保存在internal目录下的包(包括自身)仅能被其父目录下的包(含所有层次的子目录)访问。
在lib目录以外导入内部包会引发编译错误。
内置工具
go build
此命令默认每次都会重新编译除标准库以外的所有依赖包。
go install
此命名会将编译结果安装到bin,pkg目录,最关键的是go install支持增量编译,在没有修改的情况下,会直接连接pkg目录中的静态包。
go get
将第三方包下载到到GOPATH列表的第一个工作空间,默认不会检查更新。
go env
显示全部或指定环境变量
go clean
清理工作目录,删除编译和安装遗留的目标文件。
参考资料:
《Go语言学习笔记》雨痕