Part1
.GO 语言安装的时候主要有三个环境变量:
GOROOT、GOPATH 和 GOBIN
通过 go env 可以查看go语言的一系列的环境变量的配置.
go env
GOROOT
:代表go的安装路径,一般你安装完go语言之后就有了。
GOPATH
:一个目录路径,也可以包含多个目录路径,每个目录都代表了go语言的一个“工作区”。目录下面有三个目录,src,bin,pkg。
src
: 用来存放源代码文件。
bin
: 目录里面存放的都是通过 go install 命令安装后,由 Go 命令源码文件生成的可执行文件。
有两种情况下,bin 目录会变得没有意义。
当设置了有效的 GOBIN 环境变量以后,bin 目录就变得没有意义。
如果 GOPATH 里面包含多个工作区路径的时候,必须设置 GOBIN 环境变量,否则就无法安装 Go 程序的可执行文件。
pkg:用来存放通过 go install 命令安装后的代码包的归档文件(.a 文件)
GOBIN:存放可执行文件的文件目录。
Go 的源码文件分类:
(1)命令源码文件:
声明自己属于 main 代码包、包含无参数声明和结果声明的 main 函数。
命令源码文件被安装以后,GOPATH 如果只有一个工作区,那么相应的
可执行文件会被存放当前工作区的 bin 文件夹下;如果有多个工作区,
就会安装到 GOBIN 指向的目录下。
(2)库源码文件
库源码文件就是不具备命令源码文件上述两个特征的源码文件。存在于某个代码包中的普通的源码文件。
(3)测试源码文件
名称以 _test.go 为后缀的代码文件,并且必须包含 Test 或者 Benchmark 名称前缀的函数。
详情可以参照
理解内容:
- pkg 目录是用来存放通过 go install 命令安装后的代码包的归档文件(.a 文件)。归档文件的名字就是代码包的名字。所有归档文件都会被存放到该目录下的平台相关目录中,即在
$GOPATH/pkg/$GOOS_$GOARCH
中,同样以代码包为组织形式。同时这里有两个隐藏的环境变量,GOOS
和GOARCH
。这两个环境变量是不用我们设置的,系统就默认的。GOOS
是 Go 所在的操作系统类型,GOARCH
是 Go 所在的计算架构。平台相关目录是以$GOOS_$GOARCH
命名的,Mac 平台上这个目录名就是 darwin_amd64。 - 命令源码文件并不一定必须放在 src 文件夹中的。
这里需要纠正一个错误的观点:“所有的 Go 的代码都要放在 GOPATH 目录下”(这个观点是错误的)
其中go源码文件包含以下三种:
- 命令源码文件:声明自己属于 main 代码包、包含无参数声明和结果声明的 main 函数。----main包
两个main包的go文件可以单独go run运行, 但是不能go build 运行,因为go run时只运行当前文件,go build会编译当前包内所有文件。所以 go install 也不可以。 - 库源码文件:库源码文件就是不具备命令源码文件上述两个特征的源码文件。存在于某个代码包中的普通的源码文件。库源码文件被安装后,相应的归档文件(.a 文件)会被存放到当前工作区的 pkg 的平台相关目录下。
- 测试源码文件
名称以 _test.go 为后缀的代码文件,并且必须包含 Test 或者 Benchmark 名称前缀的函数。
func TestXXX( t *testing.T) {
}
名称以 Test 为名称前缀的函数,只能接受 *testing.T 的参数,这种测试函数是功能测试函数。
func BenchmarkXXX( b *testing.B) {
}
名称以 Benchmark 为名称前缀的函数,只能接受 *testing.B 的参数,这种测试函数是性能测试函数。
因此:命令源码文件是可以单独运行的。可以使用 go run 命令直接运行,也可以通过 go build 或 go install 命令得到相应的可执行文件。所以命令源码文件是可以在机器的任何目录下运行的。
包名 main 则告诉我们它是一个可独立运行的包,它在编译后会产生可执行文件。除了 main 包之外,其它的包最后都会生成 *.a 文件(也就是包文件)并放置在 $GOPATH/pkg/$GOOS_$GOARCH
中(以 Mac 为例就是$GOPATH/pkg/darwin_amd64
)。
go run
中间产生两个临时文件。
go build
go build 用于编译我们指定的源码文件或代码包以及它们的依赖包。,但是注意如果用来编译非命令源码文件,即库源码文件,go build 执行完是不会产生任何结果的。这种情况下,go build 命令只是检查库源码文件的有效性,只会做检查性的编译,而不会输出任何结果文件。
go build 编译命令源码文件,则会在该命令的执行目录中生成一个可执行文件
go run 和go build的前几步都一样,只是最后go run 执行可执行文件,go build 不执行。
- 如果构建的是库源码文件,那么操作的结果文件只会存在于临时目录中。这里的构建的主要意义在于检查和验证。也就是构建了临时目录,然后就丢弃了。如果有问题就会报出来,如果没问题就相当于一顿操作后什么都没变化,就是上面说的加和验证。
- 如果构建的是命令源码文件,那么操作的结果文件会被搬运到那个源码文件所在的目录中。一般构建就是用来做这个事情的。
go install
go install 命令是用来编译并安装代码包或者源码文件的。
安装操作会先执行构建,然后还会进行链接操作,并且把结果文件搬运到指定目录。
前面几步依旧和 go run 、go build 完全一致,只是最后一步的差别,go install 会把命令源码文件安装到当前工作区的 bin 目录(如果 GOPATH 下有多个工作区,就会放在 GOBIN 目录下)。如果是库源码文件,就会被安装到当前工作区的 pkg 的平台相关目录下。
例如:go install github.com/labstack/echo
- 如果是命令源码文件会安装在当前工作区GOPATH的bin下echo的可执行文件。
- 如果是库源码文件则安装到当前工作区GOPATH/pkg/当前平台/github.com/labstack/echo.a 文件。
go install 命令不支持针对库源码文件的安装操作。
go get
go get 命令会把当前的代码包下载到 $GOPATH 中的第一个工作区的 src 目录中,并安装。
如果在 go get 下载过程中加入-d 标记,那么下载操作只会执行下载动作,而不执行安装动作。
-u标记,加上它可以利用网络来更新已有的代码包及其依赖包。
小结
- 命令源码文件,通过构建或安装都可以完成编译,只是生成的可执行文件的目录不同。一般就用构建了,可以带参数指定位置。
- 库源码文件,只有通过安装才能在pkg中生成包文件。
- 一般就是构建源码文件。库文件的话就是进行安装。
问题
- Go 语言在多个工作区中查找依赖包的时候是以怎样的顺序进行的?
- 如果有多个工作区,那么是按照GOPATH里面的先后顺序查找的
- 如果在多个工作区中都存在导入路径相同的代码包会产生冲突吗?
- 不会冲突,像上面说的会按照顺序查找执行
- 如果我的src下面的文件夹名字叫做hello,但package的名字叫做HelloGO
package HelloGo
import "fmt"
func PrintHello(){
fmt.Println("Hello Go")
}
这时候如果你想调用这个包,代码应该怎么写,
import HelloGo?
还是import hello
答案肯定是import hello的,因为GOPATH的特性,只会按照目录来查找包,但你调用的时候就不能用目录名字来调用了:
package main
import "fmt"
import "hello"
func main() {
fmt.Println("Hello, world!")
HelloGo.PrintHello() //导入包的时候用文件夹名字,调用函数用package的名字
}
go build 命令
在运行go build命令的时候,默认不会编译目标代码包所依赖的那些代码包,如果归档文件已经存在的话。如果被依赖的代码包的归档文件不存在,或者源码文件有了变化,那它还是会被编译。常用参数说明:
-a : 可以强制编译依赖的代码包
-i : 不但要编译依赖的代码包,还要安装它们的归档文件
-x : 查看go build命令具体执行了哪些操作
-n : 同上,只查看操作,但是不实际执行
-v : 可以看到go build命令编译的代码包的名称。搭配-a参数使用时很有用
go get 命令
命令go get会自动下载代码包,并把它们安装到环境变量GOPATH包含的第1工作区的相应目录中。如果存在环境变量GOBIN,那么仅包含命令源码文件的代码包会被安装到GOBIN指向的那个目录。常用参数说明:
-u : 下载并安装代码包,不论是否已存在
-d : 只下载代码包,不安装代码包
-fix : 在下载代码包后先运行一个用于根据当前Go语言版本修正代码的工具,然后再安装代码包
-t : 同时下载测试所需的代码包
-insecure : 允许通过非安全的网络协议下载和安装代码包。比如:HTTP。
自定义代码包远程导入路径
如果你想把你编写的(被托管在不同的代码托管网站上的)代码包的远程导入路径统一起来,或者不希望让你的代码包中夹杂某个代码托管网站的域名,那么你可以选择自定义你的代码包远程导入路径。这种自定义的实现手段叫做“导入注释”。
比如代码实际存储的位置是:github.com/golang/sync/
但是安装的时候实际使用的命令是:go get golang.org/x/sync。这里就隐藏了github.com的域名,以及后面的部分路径golang。
导入注释
导入注释必须出现在源码文件的代码包声明语句的右边,是一条单行注释。被双引号包裹的是一个符合导入路径语法规则的字符串。下面是 github.com/golang/sync 下 semaphore/semaphore.go 里的导入注释:
package semaphore // import “golang.org/x/sync/semaphore”
这样加入导入注释后,就无法用github的地址来下载这个包了。但是也无法用自定义的路径来下载这个包,应该自定义的路径的网址还不能响应这个请求
编写网站的处理请求
编写一个可处理HTTP请求的程序。将对这个url响应的请求头中加入如下的一行内容:
这行内容会被视为HTML文档的元数据。这个就是go get命令的文档中要求的写法。它的模式是这样的:
content属性中的import-prefix的位置上填入自定义的远程代码包导入路径的前缀。而vsc代表与版本控制系统有关的标识,比如git。至于repo-root,它应该是与该处理程序关联的路径对应的Github网站的URL,即实际网址。
这么做的好处是,可以强化你的品牌,而不是某个代码托管网站的。顺便还可以隐藏掉用户ID,也就是域名后的部分路径。
最主要的是,使你的代码包导入路径整齐划一,如果代码包分散在不同的远程路径的话。