工程管理
1. 编程环境
1.1 工程结构
1.1.1 环境变量
- $GOROOT
$GOROOT是Go的安装根目录。
- $GOPATH
$GOPATH是Go语言编程的工作目录。
- GOBIN
$GOBIN是带有main函数的源程序执行go install时生成的可执行程序的安装目录,默认是$GOPATH/bin。
- GOOS和GOARCH
$GOOS用来设置目标操作系统,$GOARCH用来设置目标平台的 CPU 体系结构。这两个参数多用在交叉编译。
使用go env命名查看Go的编程环境

1.1.2 工作目录
$GOPATH变量所指定的目录称为Go的工作目录,$GOPATH可以配置多个目录,工作目录有相同的目录结构,内含三个子目录:

src是工程源码所在目录,一般src下的第一层目录是工程根目录,工程根目录一般采用公司的域名+工程名或用户名的形式,比如常见的GitHub上的工程源代码组织形式:
# 如下都是工程根目录
$GOPATH/src/github.com/github/
$GOPATH/src/github.com/golang/
工程根目录下才是工程各个项目的目录,项目目录下可以是其源码文件和各种包的源码。例如$GOPATH/src/github.com/github/gh-ost,$GOPATH/src/github.com/github/是GitHub工程根目录,gh-ost是具体的项目目录,gh-ost内是该项目的源代码和包。
$GOPATH环境变量可以配置多个目录,使用go get下载第三方包时,默认会将包下载到$GOPATH的第一个目录。
1.2 交叉编译
- Go 1.4 及以前版本
在 Go 1.4 及以前版本中,要在当前平台构建一个目标平台的编译环境,然后才能通过设置 GOOS和GOPATH进行交叉编译。
# 进入 Go 源码目录
$ cd /usr/local/go/src
# 在 linux 下构建 Windows 交叉编译环境
$ CGO_ENABLED=0 GOOS=windows GOARCH=amd64 ./make.bash
# 交叉编译
$ CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build xxx.go
- Go 1.5 及以后版本
只需要设置GOOS和GOARCH变量就可以轻松进行交叉编译。
编译成Linux目标文件:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build xxx.go
编译成windows目标文件:
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build xxx.go
2. 命名空间和作用域
2.1 命名空间
一个标识符可以在多个命名空间中定义,它在不同命名空间中的含义是互不干扰的。
Go语言处理包级别的显式的命名空间,还有隐式的命名空间。函数、方法、以及if、for、switch等和“{}”一起构成一个个代码块,代码块可以嵌套,每一个代码块都构成一个隐式的命名空间。
不同命名空间可以声明相同的标识符,所以不同的隐式的命名空间同样允许声明相同的标识符(包括变量),这里就有变量覆盖的问题。
2.2 作用域
作用域可以理解为变量的作用范围。Go 语言是静态作用域语言,及变量的作用域不依赖程序执行时的因素,变量的作用域在编译器就能确定。
Go 语言有三种类型的作用域:
- 全局作用域
在任何地方都可以访问的标识符,称其有全局作用域。在 Go 语言中,全局作用域有两类:
(1)Go 语言内置的预声明标识符,他们有全局作用域,在任意包内可见。
(2)Go 语言包内以大写字母开头的标识符,他们有全局作用域,在任意命名空间都可见。
- 包内作用域
在 Go 语言包内定义的以小写字母开头的标识符,他们在本包可见,在其他包不可见,这些标识符具有包作用域。
- 隐式作用域
每个代码块内定义的变量称为局部变量,这些局部变量只在当前代码块内可见,其作用域属于当前代码块的隐式作用域。
2.3 变量覆盖
Go 编译器能够解析变量名到引用实体采用的是从里到外的搜索模式,里层的局部变量能够覆盖外层变量,使得外层的同名变量不可见,这种现象称为变量覆盖。
3. 包的基本概念
Go 语言是使用 包来组织源代码的,并实现命名空间的管理。任何源代码文件必须属于某个包。
3.1 基本概念
一般包的名称就是其源文件所在目录的名称,虽然 Go 没有强制包名必须和其所在的目录同名,但还是建议包名和所在的目录同名,这样结构更加清晰。
包的定义是不包括目录路径的,但是包的引用一般是全路径引用。比如在$GOPATH/src/a/b/下定义一个包 c,在包 c 的源码中只需要声明为package c,而不是声明为package a/b/c,但是在import包 c时,需要带上路径import "a/b/c"。
包的习惯用法:
- 包名一般是小写的,使用一个简短的命名
- 包名一般要和所在的目录同名
- 包一般放到公司的域名目录下,这样能保证包名的唯一性,便于共享代码。
3.2 包引用
标准包的源码位于$GOROOT/src/下面,标准包可以直接引用。自定义包和第三方包的源码必须放到$GOPATH/src目录下才能被引用。
包引用路径
包的引用路径有两种写法,一种是全路径,另一种是相对路径。
- 全路径引用
包的绝对路径就是$GOROOT/src或$GOPATH/src后面包的源码的全路径,比如下面的包引用。
import "lab/test"
import "database/sql/driver"
import "database/sql"
test包是自定义的包,其源码位于$GOPATH/src/lab/test目录下。sql和driver包分别位于$GOROOT/src/database/sql 和$GOROOT/src/database/sql/driver下。
- 相对路径引用
相对路径只能引用$GOPATH下的包,标准包的引用只能使用全路径引用。比如下面两个包的路径分别为$GOPATH/src/llab/a和$GOPATH/src/llab/b,假设b引用了a包,则可以使用相对路径引用方式。
// 相对路径引用
import "../a"
// 绝对路径引用
包引用格式
包引用有四种格式
- 标准引用方式
import "fmt"
- 别名引用方式
import F "fmt"
- 省略方式
import . "fmt"
此时相当于把包fmt的命名空结直接合并到当前程序的命名空间中,使用fmt包内可导出的元素可以不用前缀fmt.,直接引用。
- 仅执行包初始化
init函数
使用标准格式引用包,但是代码中没有使用包,编译器会报错。如果包中有init初始化函数,则通过import _ "packageName"这种方式引用包,仅执行包的初始化函数,即使包没有init初始化函数,也不会引发编译器报错。
注意
- 一个包可以有多个
init函数,包加载会执行全部的init函数,但并不能保证执行顺序。 - 包不能出现环形引用。比如包
a引用了包b,包b引用了包c,包c引用了包a,则编译不能通过。 - 包的重复引用时允许的。比如包
a引用了包b和包c,包b和包c都引用了包d。这种场景相当于重复引用了d,这种情况是允许的,并且Go编译器保证d的init函数只执行一次。
3.3 包加载
在执行main.main之前,Go 引导程序会先对整个程序的包进行初始化。真个执行流程如图所示:

单个包的初始化过程如上图,先初始化常量,然后是全局变量,最后执行包的init函数。
4. 第三方包管理
项目中经常会引用大量第三方库,使用go get可以轻松轻松下载并安装第三方的库到本地。但是如果第三方库更新,并行新版本和旧版本不兼容。此时旧需要对第三方库进行更精细的管理,即对第三方库的版本做更精确的管控。
4.1 vendor
vendor将原来放在$GOPATH/src的第三方包放到当前工程的vendor目录进行管理,多个工程可以独立地管理自己第三方依赖包,他们直接不会项目影响。vendor将原来包共享模式转换为每个工程独立了地维护模式,vendor的另一个好处是保证了工程目录下代码地完成行,将工程代码赋值到其他 Go 扁你环境,不需要再去下载第三方包,直接就能编译。
Go1.5 需要手动设置环境变量GO15VENDOREXPERIMENT=1,Go 编译器才能引用verdor。Go1.6默认开启vendor目录。
整个查找第三方包的流程如下:
- 如果当前包下有
vendor目录,则从其下查找第三方的包,如果没有找到,继续执行下一步操作。 - 如果当前包下没有
vendor目录,则向上主机目录查找vendor目录,知道找到$GOPATH/src下的vendor目录,只要找到vendor目录,就去查找第三方包,如果没有继续执行下一步操作。 - 在
GOPATH下面查找依赖包 - 在
GOROOT下面查找依赖包
go get -u更新第三方包,默认是将工最新版本拉取到本地。而vendor无法进行版本控制,为解决该问题,引入了dep。
4.2 dep
go get能够快速拉取一个第三方的包,如果是正式工程项目,则建议使用dep进行包管理。
因网络原因,无法进行下载,请自行下载学习。
446

被折叠的 条评论
为什么被折叠?



