Go 语言编程 — go 指令

目录

go 指令

Golang 本身就是一个程序,包含了编译器以及一些辅助指令。

go run 试运行

go run 会快速执行指定的 .go 源码文件,包括:编译并运行命令源码文件,但不会生成二进制文件,常用于试运行代码。

go build 编译

go build 用来编译指定 packages 里的源码文件以及它们的依赖包,生成二进制文件。编译的时候会到 $GOPATH/src/{package_name} 路径下寻找源码文件。

例如:

go build util

编译程序会去 $GOPATH/src 路径找 util 包。还可以在 ./src/util 目录下直接执行 go build 编译。

此外,go build 还可以直接编译指定的源码文件,也可以同时指定多个源码文件。

Golang 的源码文件分为三类:

  1. 命令源码:/cmd 文件,Go 程序的入口。
  2. 库源码:/pkg 文件,主要是各种函数、接口等。go build 命令在编译只包含库源码文件的代码包时,只会做检查性的编译,而不会输出任何结果文件。所以,直接编译库源码文件不会生成 .a 文件。
  3. 测试源码:*_test.go 文件。go build 会忽略其中的测试源码文件。
go build [-o output] [-i] [build flags] [packages]
  • -o:只在编译单个包的时候出现,它指定输出的可执行文件名。
  • -i:会安装编译目标所依赖的包,安装是指生成与代码包相对应的 .a 文件,即静态库文件,并且放置到当前工作区的 pkg 目录下,且库文件的目录层级和源码层级一致。

至于 build flags 参数,build、clean、get、install、list、run、test 这些命令共用一套:

在这里插入图片描述

展示整个编译链接的运行过程可以执行:

go build -v -x -work -o bin/hello src/main.go
  • -v:打印所编译过的包名字。
  • -x:打印编译期间所执行的命令。
  • -work:打印编译期间生成的临时文件路径,并且编译完成之后不会被删除。

整体来看, go build 在执行时,会先递归寻找 main.go 所依赖的包,以及依赖的依赖,直至最底层的包。这里可以是深度优先遍历也可以是宽度优先遍历。如果发现有循环依赖,就会直接退出,这也是经常会发生的循环引用编译错误。

go install 安装

当我们编写好 Go 程序之后可以使用 go install 来安装他,会自动生成可执行文件,并放到操作系统的 $GOPATH/bin 目录下。当然了,前提是我们编译的是可执行文件,如果是一个普通的包,会被编译生成到 $GOPATH/pkg 目录下该文件以 .a 结尾。

相比 go build,go install 只是多了一个 “安装编译后的结果文件到指定目录” 的步骤。

示例:

$ cd $GOPATH/src/helloworld

$ go install

$ ll $GOPATH/bin
-rwxr-xr-x  1 mickeyfan  staff   2.1M  7 11 18:03 helloworld

$ helloworld
Hello World!

go get 下载并安装

go get 会做两件事情:

  1. 从远程下载需要用到的包。
  2. 执行 go install 指令。
$ go get golang.org/x/tools/cmd/goimports

$ ll $GOPATH/src
drwxr-xr-x   3 mickeyfan  staff    96B  7 11 21:50 golang.org

$ ll $GOPATH/bin
-rwxr-xr-x  1 mickeyfan  staff   5.6M  7 11 21:51 goimports
  • 下载项目依赖
go get ./...
  • 查看可下载版本
go list -m -versions github.com/gogf/gf
  • 拉取最新的版本
go get golang.org/x/text@latest
  • 拉取 master 分支的最新 commit
go get golang.org/x/text@master
  • 拉取 tag 为 v0.3.2 的 commit
go get golang.org/x/[email protected]
  • 拉取 hash 为 342b231 的 commit,最终会被转换为 v0.3.2
go get golang.org/x/text@342b2e
  • 指定版本拉取,拉取 v3 版本
go get github.com/smartwalle/alipay/v3
  • 更新
go get -u

go test 测试

go test 用于执行单元测试或压力测试。

go env 环境变量

go env 显示 Golang 运行环境的环境变量。

$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/mickeyfan/Library/Caches/go-build"
GOENV="/Users/mickeyfan/Library/Application Support/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/mickeyfan/workspace/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/q4/q1nznqls7pj82ylx424ms0q40000gn/T/go-build255965584=/tmp/go-build -gno-record-gcc-switches -fno-common"

go fmt 格式化源代码

Golang 程序代码的大部分格式问题都可以通过 go fmt 指令来解决。go fmt 会自动格式化代码,保证所有的 Go 代码与官方推荐的格式保持一致,所有格式有关问题,都以 go fmt 的执行结果为准。所以,建议在提交代码库之前先运行一下这个命令。

go mod 依赖包管理

go mod 是 Golang 1.11 版本引入的依赖包管理工具。其中,Golang 对 Modules 的定义:Modules 是相关 Go Packages 的集合,是源代码交换和版本控制的单元。

go 指令支持使用 Modules,包括记录和解析对其他模块的依赖性。Go Modules 替换旧的基于 GOPATH 的依赖管理方式,不再需要包含例如:src,bin 这样的子目录,一个源代码目录甚至是空目录都可以作为 Modules,只要其中包含了 go.mod 文件。

go.mod 文件一旦创建后,它的内容将会被 go toolchain 全面掌控。go toolchain 会在各类命令执行时,比如:go get、go build、go mod 等修改和维护 go.mod 文件。使用 go.mod 方式管理的依赖包都被下载到了 $GOPATH/pkg/mod 目录:

$ ll $GOPATH/pkg/mod/
total 0
drwxr-xr-x   3 mickeyfan  staff    96B  7 12 17:50 9fans.net
drwxr-xr-x   4 mickeyfan  staff   128B  7 12 18:05 cache
drwxr-xr-x  69 mickeyfan  staff   2.2K  7 12 18:12 github.com
dr-x------  16 mickeyfan  staff   512B  7 12 17:51 [email protected]
drwxr-xr-x   3 mickeyfan  staff    96B  7 12 17:49 golang.org
drwxr-xr-x   6 mickeyfan  staff   192B  7 12 17:52 gopkg.in
drwxr-xr-x   3 mickeyfan  staff    96B  7 12 17:50 honnef.co
drwxr-xr-x   7 mickeyfan  staff   224B  7 12 17:52 mvdan.cc
drwxr-xr-x   3 mickeyfan  staff    96B  7 12 17:52 sourcegraph.com

除了 go.mod 之外,go 指令还维护了一个 go.sum 文件,其中包含特定模块版本内容的加密哈希。go 指令使用 go.sum 文件来确保这些模块的哈希值,以确保项目所依赖的模块不会出现意外更改。go.mod 和 go.sum 都应该应用于版本控制。 并且 go.sum 不需要手工维护,所以可以不用太关注。

使用 go mod

使用 Go Modules 需要配置 GO111MODULE 环境变量,GO111MODULE 有三个值:off、on 和 auto(默认值):

  • GO111MODULE=off:go 指令不支持 Modules 功能,寻找依赖包的方式依旧沿用旧版本那种通过 vendor 目录或者 GOPATH 环境变量来查找。
  • GO111MODULE=on:go 指令使用 Modules 方式,而不再到 GOPATH 目录下查找依赖包。
  • GO111MODULE=auto:go 指令根据当前目录来决定是否启用 Modules 功能。这种情况下可以分为两种情形:
    • 当项目处于 GOPATH/src 内,则会使用 GOPATH/src 的依赖包。
    • 当项目处于 GOPATH/src 外,则使用 go.mod 里 require 声明的包。

建议开启:

export GO111MODULE=on

使用 go.mod 的流程:

  1. 首先要在 GOPATH/src 目录之外新建 Golang 项目。
  2. 创建 main:
package main

import "fmt"

func main() {
	fmt.Println("hello world!")
}
  1. 初始化项目的 go.mod
$ go mod init hello

module hello

go 1.14

注意,项目下属的子目录是不需要再次 init 的,所有子目录里的依赖都会组织在根目录的 go.mod 文件里。

  1. 导入外部包:
package main

import (
	"fmt"
	"github.com/gohouse/gorose"
)

func main() {
	fmt.Println("hello world!")
}
  1. 运行程序:
$ go run hello.go
go: finding module for package github.com/gohouse/gorose
go: downloading github.com/gohouse/gorose v1.0.5
go: found github.com/gohouse/gorose in github.com/gohouse/gorose v1.0.5
go: finding module for package github.com/gohouse/converter
go: downloading github.com/BurntSushi/toml v0.3.0
go: downloading github.com/gohouse/converter v0.0.3
go: found github.com/gohouse/converter in github.com/gohouse/converter v0.0.3
go: downloading github.com/go-sql-driver/mysql v1.4.0
# command-line-arguments
./hello.go:5:5: imported and not used: "github.com/gohouse/gorose"
  1. 检查 go.mod 自动依赖清单维护
module hello

go 1.14

require (
	github.com/gohouse/converter v0.0.3 // indirect
	github.com/gohouse/gorose v1.0.5 // indirect
)

其中 require 是一个关键字,此外还有 module、replace 和 exclude:

  • module 语句:指定包的名字(路径)。
  • require 语句:指定的依赖项模块。
  • replace 语句:可以替换依赖项模块。
  • exclude语句:可以忽略依赖项模块。

另外,上述的 v0.0.3 就是依赖包 converter 的版本。如果没有在 go.mod 指定版本,go 指令就会自动下载代码中的依赖的最新版本。否则,go 指令会根据 require 语句的路径和版本进行下载。指定版本时也可以用 latest,表示下载最新的版本。

replace 语句常用于依赖包实际路径变更的场景中,例如:

replace golang.org/x/text => github.com/golang/text latest

如此的,在这种情况下依赖包的维护会变得更简单。

还需要注意 go.mod 中的 module hello 这一条语句,因为当前项目已经不在 GOPATH/src 内了,所以 module hello 标注了项目 “根” 的路径,以此来作为项目中其他包的根路径。

同时,go mod 指令也提供了以下子指令:
在这里插入图片描述

  • 初始化一个 moudle
go mod init <project_name>
  • 下载 modules 到本地 Cache
go mod download

注:目前所有模块版本数据均缓存在 GOPATH/pkg/mod 和 GOPATH/pkg/sum 下。

  • 编辑 go.mod 文件,选项有 -json、-require 和 -exclude
go mod edit
# e.g.
go mod edit -replace=golang.org/x/[email protected]=github.com/golang/crypto@latest
  • 以文本模式打印模块需求图
go mod graph
  • 删除错误或者不使用的 modules
go mod tidy
  • 生成 vendor 目录
go mod vendor
  • 验证依赖是否正确
go mod verify
  • 查找依赖
go mod why
  • 清理 modules 缓存
go clean -modcache

猜你喜欢

转载自blog.csdn.net/Jmilk/article/details/107288501