GO语言学习笔记-包结构篇 Study for Go ! Chapter eight - Package Structure
- GO语言学习笔记-函数篇 Study for Go ! Chapter three - Function
- GO语言学习笔记-数据篇 Study for Go ! Chapter four - Data
- GO语言学习笔记-方法篇 Study for Go ! Chapter five - Method
- GO语言学习笔记-接口篇 Study for Go ! Chapter six - Interface
- GO语言学习笔记-并发篇 Study for Go ! Chapter seven - Concurrency
- GO语言学习笔记-包结构篇 Study for Go ! Chapter eight - Package Structure
- GO语言学习笔记-反射篇 Study for Go ! Chapter nine - Reflect
- GO语言学习笔记-测试篇 Study for Go ! Chapter ten- Test
- GO语言学习笔记-工具链篇 Study for Go ! Chapter eleven - Tool Chain
1. Workspace
-
工作空间主要由 src、bin、pkg 三个目录组成。通常需要将空间路径添加到 GOPATH 环境变量列表中,一遍相关工具能正常工作
-
在工作空间里,包括子包在内的所有源码文件都保存在 src 目录下。至于bin、pkg两个目录,其主要影响 go install/get 命令,它们会将编译结果 (可执行文件或静态库)安装到这两个目录下,以实现增量编译
环境变量
-
编译器等相关工具按 GOPATH 设置的路径搜索目标。也就是说在导入目标库时,排在列表前面的路径比当前工作空间优先级更高
-
另外,go get 默认将下载的第三方包保存到列表中第一个工作空间内
-
-
环境变量 GOROOT 用于指示工具链和标准库的存放位置。在生成工具链时,相关路径就已经嵌入到可执行文件内,故无须格外设置,但如果出现类似下面这样的错误提示,请检查路径是否一致
-
-
除通过设置 GOROOT 环境变量覆盖内部路径外,还可以移动目录 (改名、符号连接等),或重新编译工具链来解决
-
至于 GOBIN ,则是强制代替工作空间的 bin 目录,作为 go install 目标保存路径,这可避免将所有工作空间的 bin 路径 添加到 PATH 环境变量中
-
在使用 Git 等版本控制工具时,建议忽略 pkg、bin 目录。直接在 src, 或具体的子包下创建代码仓库 (repository)
2. 导入包
-
使用标准库或第三方包前,需使用 import 导入,参数是工作空间中以 src 为七十的绝对路径。编译器从标准库开始搜索,然后依次搜索 GOPATH 列表中的各个工作空间
-
除了使用默认包名外还可以使用别名,以解决同名冲突问题
Attention;
-
import 导入参数是路径,而非包名,尽管习惯将包和目录名保持一致,但这不是强制规定,在代码中引用包成员时,使用包名而非目录名
-
有四种导入方式
-
默认方式
-
别名方式
-
简便方式 (常用于单元测试代码中,不推荐在正式项目于代码中使用。)
-
初始化方式 (无法引用,仅用来初始化目标包,让目标包的初始化函数得以执行)
不能直接或者间接导入自己,不支持任何形式的循环导入
-
-
未使用的导入(不包含初始化方式)会被编译器视为错误
相对路径
-
除了工作空间和绝对路径外,部分工具还支持相对路径。可在非工作空间目录下,直接运行,编译一些测试代码
-
相对路径是指:当前目录,或以“ ./ ” 和 “ ../ ” 开头的路径
-
不管是否在 test 目录下,只要命令行路径正确,就可以用go build/run/test 进行编译,运行或测试。但因缺少工作空间相关目录,go install 会无法工作
-
在设置了 GOPATH 的工作空间中,相对路径会导致编译失败
-
go run 不受此影响,可正常执行
自定义路径
-
即便将代码托管在 GitHub ,但我们依然希望使用自有域名定义下载和导入路径。方法很简单,在 Web 服务器对应路径返回中包含 “ go-import ” 跳转信息即可
-
使用唯一的导入路径,方便日后迁移存储端,但此方法对 vendor 机制无效
-
3. 组织结构
-
包由一个或多个保存在同一目录下(不含子目录)的源码文件组成。包的用途类似名字空间(namespace),是成员作用域和访问权限的边界
-
包名和目录名并无关系,不要求保持一致
-
包名常用单数形式
-
源码文件必须使用 UTF-8 格式,否则会导致编译出错
-
同一目录下所有源码文件必须使用相同包名称,因导入是使用绝对路径,所以在搜索路径下,包必须有唯一路径,但无须是唯一名字
有几个被保留、有特殊含义的包名称;
-
main:可执行入口(入口函数 mian.mian)
-
all:标准库以及 GOPATH 中能找到的所有包
-
std,cmd:标准库及工具链
-
documentation:储存文档信息,无法导入(和目录名无关)
(相关工具忽略以” . “ 或 ” _ “ 开头的目录或文件,但是又允许导入保存在这些目录中的包! )
权限
-
所有成员在包内均可访问,无论是否在同一源码文件中。但只有名称首字母大写的为可导出成员,在包外可视 (该规则适用于全局变量、全局常量、类型、结构字段、函数、方法等)
-
可通过指针转换等方式绕开该限制
初始化
-
包内每个源码文件都可定义一到多个初始化函数,但编译器不保证执行次序。
-
实际上,所有这些初始化函数(包括标准库和导入的第三方包)都由编译器自动生成的一个包装函数进行调用,因此可保证在单一线程上执行,且只执行一次
-
编译器首先确保完成所有全局变量初始化,然后才开始执行初始化函数,知道这些全部结束后,运行时才正式进入 main.main 入口函数
-
可以在初始化函数中创建 goroutine,或等到它执行结束
-
如果在多个初始化函数中引用全局变量,那么最好在变量定义出直接赋值,因无法保证执行次序,所以任何初始化函数中的赋值都有可能“ 延迟无效 ”
延迟包
-
在进行代码重构时,我们会将一些内部模块陆续分离出来,以独立包形式维护。此时,基于首字母大小写的访问权限控制就显得过于粗犷。因为我们希望这些包导出成员仅在特定范围内访问,而不是向所有用户公开
-
内部包机制相当于增加了新的访问权限控制:所有保存在 internal 目录下的包 ( 包括自身 )仅能被其父目录下的包 ( 含所有层次的子目录 )访问
-
导入内部包必须使用完整路径
-
4. 依赖管理
-
如何管理和保存第三方包,一致存在争议。将项目所有的第三方依赖都放到一个独立工作空间中,可能会导致版本冲突。放到项目工作空间,又会把工作目录搞的面目全非。为此,引入了名为 vendor 的机制,专门存放第三方包,实现将源码和依赖完整打包分发
-
如果说 internal 针对内部,那么 vender 就是 针对外部 (external)
-
导入 vendor 中的第三方包,参数是以 vendor/ 为起点的绝对路径。这就避免了 vendor 目录位置带来的麻烦,让导入无论使用 vender,还是 GOPATH 都能保持一致
ATTENTION
-
vendor 比标准库优先级更高
question:当多个 vendor 目录嵌套时,如何正确查找目标 ?要知道引入的第三方包也可能存在有自己的 vendor 依赖目录
answer:从当前源文件所在目录开始,逐级向上构造 vendor 全路径,知道发现路径匹配的目标为止。匹配失败,则依旧搜索 GOPATH
-
要使用 vendor机制,须开启 ” GO15VENDOREXPERIMENT=1 “ 环境变量开关 ( GO 1.6 以上默认开启 )且必须是设置了 GOPATH 的工作空间
使用 go get 下载第三方包时,依旧使用 GOPATH 第一个工作空间,而非 vendor 目录。当前工具链中并没有真正意义上的包管理依赖,好在有不少的第三方工具可以选择
本文来自博客园,作者:slowlydance2me,转载请注明原文链接:https://www.cnblogs.com/slowlydance2me/p/17198519.html