这是我参加「第三节青训营~后端场」笔记创作活动的第1篇笔记
go的配置
GOPATH设置
go语言有许多关键字,其中一个很重要的关键字就是“go”。 go 命令依赖一个重要的环境变量:$GOPATH,
GOPATH允许多个目录,当有多个目录时,请注意分隔符,多个目录的时候Windows是分号,Linux系统是冒号,当有多个GOPATH时,默认会将go get的内容放在第一个目录下。
以上 $GOPATH 目录约定有三个子目录:
- src 存放源代码(比如:.go .c .h .s等)
- pkg 编译后生成的文件(比如:.a)
- bin 编译后生成的可执行文件(为了方便,可以把此目录加入到 {GOPATH//://bin:}/bin`添加所有的bin目录)
代码目录结构规划
GOPATH下的src目录就是接下来开发程序的主要目录,所有的源码都是放在这个目录下面,那么一般我们的做法就是一个目录一个项目,例如: $GOPATH/src/mymath 表示mymath这个应用包或者可执行应用,这个根据package是main还是其他来决定,main的话就是可执行应用,其他的话就是应用包。
所以当新建应用或者一个代码包时都是在src目录下新建一个文件夹,文件夹名称一般是代码包名称,当然也允许多级目录,例如在src下面新建了目录$GOPATH/src/llh/pro 那么这个包路径就是"llh/pro",包名称是最后一个目录也就是pro。
注意:一般建议package的名称和目录名保持一致
执行以下代码:
cd $GOPATH/src
mkdir pro
然后在该目录下建go文件。
再编译安装应用:
有两种编译方式
1、只要进入对应的应用包目录,然后执行go install,就可以安装了
2、在任意的目录执行如下代码go install pro
安装完之后,我们可以进入如下目录
cd $GOPATH/pkg/${GOOS}_${GOARCH}
//可以看到如下文件
pro.a
这个应用没有main,所以创建一个可以调用它的程序,现在在src下创建目录app,进入app,然后创建main.go,
cd $GOPATH/src
mkdir app
cd app
vim main.go
$GOPATH/src/app/main.go源码:
package main
import (
"pro"
)
func main() {
fmt.Printf("Hello, world. Sqrt(2) = %v\n", pro.Sqrt(2))
}
其实这里就是引用了pro包里面的函数。
import里面调用的包是mymath,这个就是相对于$GOPATH/src的路径,如果是多级目录,就在import里面引入多级目录,如果你有多个GOPATH,也是一样,Go会自动在多个$GOPATH/src中寻找。
如何编译程序呢?进入该应用目录,然后执行go build,那么在该目录下面会生成一个app的可执行文件
./app
如何安装该应用,进入该目录执行go install,那么在GOPATH/bin`加到我们的PATH里面了,这样可以在命令行输入如下命令就可以执行
app
这个程序就运行起来了。
获取远程包--go get
go语言有一个获取远程包的工具就是go get,就类似于maven从远程的仓库获取依赖一样,
如:
go get github.com/llh/project
go get -u 参数可以自动更新包,而且当go get的时候会自动获取该包依赖的其他第三方包
通过上面获取的代码在我们本地的源码相应的代码结构如下
$GOPATH
src
|--github.com
|-llh
|-project
pkg
|--相应平台
|-github.com
|--llh
|project
go get本质上可以理解为首先第一步是通过源码工具clone代码到src下面,然后执行go install
在代码中如何使用远程包,很简单的就是和使用本地包一样,只要在开头import相应的路径就可以
import "github.com/llh/project"
简而言之呢,这就像一个maven仓库,我们想要什么就go get获取到我们gopath下,我们在项目中引用也直接在import里面导入,go会自动去你配置的gopath目录下找。
程序的整体结构
bin/
app (有main的)
pkg/
平台名/ 如:darwin_amd64、linux_amd64
project.a (安装完的包)
github.com/
llh/
pro.a
src/
app
main.go
peo/
sqrt.go
github.com/
llh/
project/
xxxxxx.go
从上面的结构我们可以很清晰的看到,bin目录下面存的是编译之后可执行的文件,pkg下面存放的是应用包,src下面保存的是应用源代码
go的常见命令
我们已经知道go有很多命令了,我们可以打开cmd输入go来查看:
go build
这个命令主要用于编译代码。在包的编译过程中,若有必要,会同时编译与之相关联的包。
-
如果是普通包,没有main的,当你执行
go build之后,它不会产生任何文件。如果你需要在$GOPATH/pkg下生成相应的文件,那就得执行go install。 -
如果是
main包,当你执行go build之后,它就会在当前目录下生成一个可执行文件exe文件。如果你需要在$GOPATH/bin下生成相应的文件,需要执行go install,或者使用go build -o 路径/a.exe。 -
如果某个项目文件夹下有多个文件,而你只想编译某个文件,就可在
go build之后加上文件名,例如go build a.go;go build命令默认会编译当前目录下的所有go文件。 -
你也可以指定编译输出的文件名。例如1.2节中的
mathapp应用,我们可以指定go build -o astaxie.exe,默认情况是你的package名(非main包),或者是第一个源文件的文件名(main包)。(注:实际上,package名在Go语言规范中指代码中“package”后使用的名称,此名称可以与文件夹名不同。默认生成的可执行文件名是文件夹名。)
-
go build会忽略目录下以“_”或“.”开头的go文件。
go clean
这个命令是用来移除当前源码包和关联源码包里面编译生成的文件。这些文件包括:
_obj/ 旧的object目录,由Makefiles遗留
_test/ 旧的test目录,由Makefiles遗留
_testmain.go 旧的gotest文件,由Makefiles遗留
test.out 旧的test记录,由Makefiles遗留
build.out 旧的test记录,由Makefiles遗留
*.[568ao] object文件,由Makefiles遗留
DIR(.exe) 由go build产生
DIR.test(.exe) 由go test -c产生
MAINFILE(.exe) 由go build MAINFILE.go产生
*.so 由 SWIG 产生
我一般都是利用这个命令清除编译文件,然后github递交源码,在本机测试的时候这些编译文件都是和系统相关的,但是对于源码管理来说没必要。
$ go clean -i -n
cd /Users/astaxie/develop/gopath/src/mathapp
rm -f mathapp mathapp.exe mathapp.test mathapp.test.exe app app.exe
rm -f /Users/astaxie/develop/gopath/bin/mathapp
参数介绍
-i清除关联的安装的包和可运行文件,也就是通过go install安装的文件-n把需要执行的清除命令打印出来,但是不执行,这样就可以很容易的知道底层是如何运行的-r循环的清除在import中引入的包-x打印出来执行的详细命令,其实就是-n打印的执行版本
go fmt
go语言的代码风格写死,如果不遵循代码规范写是不通过编译的,当然这个ide已经帮你做好了,其实底层也就是调用了go fmt
go get
这个命令是用来动态获取远程代码包的,目前支持的有BitBucket、GitHub、Google Code和Launchpad。这个命令在内部实际上分成了两步操作:第一步是下载源码包,第二步是执行go install。
go install
这个命令在内部实际上分成了两步操作:
第一步是生成结果文件(可执行文件或者.a包)
第二步会把编译好的结果移到$GOPATH/pkg或者$GOPATH/bin。
参数支持go build的编译参数。只要记住一个参数-v就好了,这个随时随地的可以查看底层的执行信息。
go test
执行这个命令,会自动读取源码目录下面名为*_test.go的文件,生成并运行测试用的可执行文件。
几个我们常用的参数:
-bench regexp执行相应的benchmarks,例如-bench=.-cover开启测试覆盖率-run regexp只运行regexp匹配的函数,例如-run=Array那么就执行包含有Array开头的函数-v显示测试的详细命令
go tool
go tool下面下载聚集了很多命令,这里只介绍两个,fix和vet
go tool fix .用来修复以前老版本的代码到新版本,例如go1之前老版本的代码转化到go1,例如API的变化go tool vet directory|files用来分析当前目录的代码是否都是正确的代码,例如是不是调用fmt.Printf里面的参数不正确,例如函数里面提前return了然后出现了无用代码之类的。