🚩 人生苦短,Let’s go ,本系列所有测试代码均托管在:代码地址

参考

Go 语言环境安装#

学习之前需要先安装GO语言的环境

  • 官网下载地址:https://golang.org/dl/
  • 官方镜像:https://golang.google.cn/dl/

Windows 平台和 Mac 平台推荐下载可执行文件版,Linux 平台下载压缩文件版。本机操作系统是 Windows,在下载地址中找到 .msi 后缀的安装包:

下载到本地并安装,建议安装到指定目录下:

通过 go version 测试是否安装成功:

C:\Users\Administrator>go version
go version go1.17.5 windows/amd64

Go 支持以下操作系统:

  • Linux
  • FreeBSD
  • MacOS
  • Windows

针对其它平台的安装需要的话自行查找相关资料。

GOPATH#

GOPATH 是一个环境变量,用来指定工作目录。所有的 go 文件,都需要放在 GoPath 下的 src 目录下才能够编译运行。但是这么做存在几个问题:

在项目中使用第三方类库时 通过 go get 命令拉取下来的包会直接下载到 GoPath 目录下的 src 包下,这就导致自己写的代码和第三方的文件混在一起,对于管理 Golang 项目的包是非常麻烦的。而且每个如果项目都需要同样的依赖,那么就会在不同的 GoPathsrc 中下载大量重复的第三方依赖包,同样会占用大量的磁盘空间。

能否通过给不同的项目设置不同的 GoPath 来解决依赖项目结构混乱问题?

这么做便于管理项目,每个项目都是不同的 GoPath ,对于管理多个项目而言,能够非常清晰的处理项目结构。否则如果把所有项目都放在同一个 GoPathsrc 包下,项目的结构就会变得非常混乱,难以管理。

但是当需要依赖第三方的包的时候,上面的方式解决不了依赖重复的问题

第三方依赖的包和自己的包混在一起,会给项目文件管理带来一定的麻烦。不同的 GoPath 都需要下载依赖,那么磁盘中重复的依赖就会非常多,会占用大量的磁盘空间。

所以,究竟是设置一个GoPath目录,解决依赖重复的问题;还是设置不同的GoPath目录,解决Golang项目结构混乱的问题,这是一个有争议性的问题。为了解决这所有的问题,Golang 最终引入了 GoModule 的概念。

Go Module#

go version<1.11前,使用 GOPATH 来构建应用,但在Go1.11版本之后不再推荐。go module 是Go语言从 1.11 版本之后官方推出的版本管理工具。

Modules 官方定义为:

Modules 是相关 Go 包的集合,是源代码交换和版本控制的单元。Go语言命令直接支持使用 Modules,包括记录和解析对其他模块的依赖性,Modules 替换旧的基于 GOPATH 的方法,来指定使用哪些源文件

注意Golang1.11和1.12 版本虽然已经引入了 GoModule 的概念,但是默认是不开启的,如果需要开启,需要配置环境变量:GO111MODULE=on,默认是 off。而在 Golang1.13 及以上的版本中,GoModule 的默认配置为 auto ,即 GoModule 会通过目录下是否有 go.mod 文件来判断是否开启 GoModule 。所以Golang1.13+ 的版本中就不再需要额外配置 GO111MODULE 属性。

  • GO111MODULE=off :禁用 go module,编译时会从 GOPATHvendor 文件夹中查找包
  • GO111MODULE=on: 启用 go module,编译时会忽略 GOPATHvendor 文件夹只根据 go.mod 下载依赖
  • GO111MODULE=auto:默认值,当项目在 GOPATH/src 目录之外,并且项目根目录有 go.mod 文件时,开启 go module

Windows 下手动开启 GO111MODULE

set GO111MODULE=on 或者 set GO111MODULE=auto

MacOS 或者 Linux 下手动开启 GO111MODULE

export GO111MODULE=on 或者 export GO111MODULE=auto

有了 GoModule 之后,GoPath 是不是就可以被舍弃了?

不是的!之前说过 GoPath 所引出的问题,就是因为第三方类库的包所导致的,所以在有了 GoModule 之后,GoPathGoModule 就分别负责不同的职责,共同为项目服务。

  • GoPath 用来存放从网上拉取的第三方依赖包
  • GoModule 用来存放自己的Golang项目文件,当项目需要依赖第三方的包时通过 GoModule 目录下的 go.mod 文件来引用 GoPath 目录 src 包下的第三方依赖即可

这样既解决了原来只能局限在 GoPath/src 包下编程的问题,也解决了第三方依赖包难以管理和重复依赖占用磁盘空间的问题。在引入 GoModule 之后,不会直接在 GoPath 目录进行编程,而是把 GoPath 作为一个第三方依赖包的仓库,真正的工作空间在 GoModule 目录下。

Go Module设置#

使用 go mod init 模块名称 命令对目录进行初始化操作,即可将这个目录设置为 GoModule 目录。

D:\GoProject>go mod init goProject

初始化命令执行完毕之后,会在 D:\GoProject> 目录下生成一个 go.mod 文件,该文件就是用来引入 GoPath 目录下的第三方依赖的文件。

初始化之后的 go.mod 文件

module goProject

go 1.17

当需要引入 GoPath 目录下的第三方依赖包的时候,只需要在 go.mod 目录下添加依赖名称,GoModule 就会自动把第三方依赖包下载到 GoPath 目录下。例如下面的 go.mod 文件:

module go_module_demo

go 1.17

require (
	github.com/astaxie/beego v1.12.1
	github.com/go-sql-driver/mysql v1.5.0
)

在这个 go.mod 文件中引入了两个依赖,分别是:beego框架 v1.12.1版本mysql驱动 v1.5.0版本

常用命令如下

命令作用
go mod download下载依赖包到本地(默认为 GOPATH/pkg/mod 目录)
go mod edit编辑 go.mod 文件
go mod graph打印模块依赖图
go mod init初始化当前文件夹,创建 go.mod 文件
go mod tidy增加缺少的包,删除无用的包
go mod vendor将依赖复制到 vendor 目录下
go mod verify校验依赖
go mod why解释为什么需要依赖

GO PROXY#

国内的网络因为防火墙的存在导致有些Go语言的第三方包无法直接通过 go get 命令获取。GOPROXY 是Go官方提供的一种通过中间代理商来为用户提供包下载服务的方式。要使用 GOPROXY 只需要设置环境变量 GOPROXY 即可。

目前公开的代理服务器的地址有:

  • goproxy.io
  • goproxy.cn:(推荐)由国内的七牛云提供

Windows 下设置 GOPROXY

go env -w GOPROXY=https://goproxy.cn,direct

MacOS 或 Linux 下设置 GOPROXY

export GOPROXY=https://goproxy.cn

Go 在 1.13 版本之后 GOPROXY 默认值为 https://proxy.golang.org,在国内可能会存在下载慢或者无法访问的情况,所以建议将 GOPROXY 设置为国内的 goproxy.cn

下载指定版本

执行 go get 命令,在下载依赖包的同时还可以指定依赖包的版本。

  • 运行 go get -u 命令会将项目中的包升级到最新的次要版本或者修订版本
  • 运行 go get -u=patch 命令会将项目中的包升级到最新的修订版本
  • 运行 go get [包名]@[版本号] 命令会下载对应包的指定版本或者将对应包升级到指定的版本

注意:go get [包名]@[版本号]命令中版本号可以是 x.y.z 的形式,例如 go get foo@v1.2.3,也可以是 git 上的分支或 tag,例如 go get foo@master,还可以是 git 提交时的哈希值,例如 go get foo@e3702bed2

Hello, World#

老规矩先搞一个 hello world 看看,创建 GoProject 目录,目录格式如下:

D:\GoProject>tree
卷 Data 的文件夹 PATH 列表
卷序列号为 189B-A748
D:.
└─src

go mod init#

使用 go module 模式新建项目时,需要通过 go mod init 项目名 命令对项目进行初始化,该命令会在项目根目录下生成 go.mod 文件。比如:

D:\GoProject\src>go mod init goProject

编写代码#

package main
import "fmt"
func main() {
   /* go 语言的hello world */
   fmt.Println("Hello, World!")
}

第一行:package main,定义包名,必须在源文件中非注释的第一行指明这个文件属于哪个包,比如:package main 表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。类似于 C# 中的 namespace,表示处于哪个命名空间下。

第二行:import "fmt",告诉 Go 编译器这个程序需要使用 fmt 包的函数或其他元素,fmt 包实现了格式化 IO(输入/输出)的函数。类似于在 C# 中需要引用其他 namespace 中的函数时需要使用 using

第三行:func main(),表示程序开始执行的函数。main 函数是每一个可执行程序所必须包含的,一般来说都是在启动后第一个执行的函数(如果有 init() 函数则会先执行该函数)。类似于C#中作为入口方法的Main()方法。

第四行:/*...*/: 注释,单行使用//,多行使用/**/ 这没什么好说的。

第五行:fmt.Println(...): 用于将字符串输出到控制台,并在最后自动增加换行字符 \n。类似于 C# 中的 Console.WriteLine() /Console.Write()

go build#

go build 命令表示将源代码编译成可执行文件。在 D:\GoProject\src> 目录下执行:

D:\GoProject\src>go build test.go
D:\GoProject\src>dir
 驱动器 D 中的卷是 Data
 卷的序列号是 189B-A748

 D:\GoProject\src 的目录

2022/01/04 周二  16:12         1,924,096 test.exe
2022/01/04 周二  15:57               111 test.go

编译得到的可执行文件会保存在执行编译命令的当前目录下,如果是windows平台会在当前目录下找到 test.exe 可执行文件。

可在终端直接执行该 test.exe 文件:

D:\GoProject\src>test.exe
Hello, World!

go run#

Go 是一门编译型语言,Go 语言的工具链将源代码及其依赖转换成计算机的机器指令(静态编译)。Go语言提供的工具都通过一个单独的命令 go 调用,go 命令有一系列子命令。最简单的一个子命令就是 run。这个命令编译一个或多个以 .go 结尾的源文件,链接库文件,并运行最终生成的可执行文件。

跨平台编译#

默认 go build 的可执行文件都是当前操作系统可执行的文件,如果想在 windows 下编译一个 linux 下可执行文件,可以这么做:

指定目标操作系统的平台和处理器架构:

SET CGO_ENABLED=0  // 禁用CGO
SET GOOS=linux  // 目标平台是linux
SET GOARCH=amd64  // 目标处理器架构是amd64

使用了cgo的代码是不支持跨平台编译的

然后再执行 go build 命令,得到的就是能够在 linux 平台运行的可执行文件了。

Mac 下编译 Linux 和 Windows平台 64位 可执行程序:

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build

Linux 下编译 Mac 和 Windows 平台64位可执行程序:

CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build

Windows下编译Mac平台64位可执行程序:

SET CGO_ENABLED=0
SET GOOS=darwin
SET GOARCH=amd64
go build

现在,开启 Go 语言学习之旅。