一、GOPATH 与 Go Modules
GOPATH 开发模式
GOPATH 是 Go 语言中使用的一个环境变量,它使用绝对路径提供项目的共工作目录,GOPATH 适合处理大量 Go 语言源码、多个包组合而成的复杂工程。
在命令行中输入 go env
可以查看 Go 的环境变量相关信息
Go 在 1.12 版本之前没有包管理的概念,所有的代码都保存在 GOPATH 的 src 目录下。
经过 go build
、go install
或者 go get
指令后,会将产生的二进制可执行文件存放在 GOPATH 的 bin 目录下,生成的中间缓存文件会保存在 GOPATH 的 pkg 目录下。
Go Modules 开发模式
Go Modules 是 Go 1.11 版本之后官方推出的版本管理工具,并且从 Go 1.13 版本开始为默认的依赖管理工具。
Go 1.11 版本开始在 GOPATH 以外的目录使用 go.mod 创建项目。使用 Go Module 管理的项目根目录中会包含 go.mod 文件,该文件为项目的依赖。
以一个 Gin Web 项目的 go.mod 为例,包含的依赖如下:
module gin-quickstart go 1.18 require ( github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-gonic/gin v1.8.1 // indirect github.com/go-playground/locales v0.14.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect github.com/go-playground/validator/v10 v10.11.0 // indirect github.com/goccy/go-json v0.9.10 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/leodido/go-urn v1.2.1 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.0.2 // indirect github.com/ugorji/go/codec v1.2.7 // indirect golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect golang.org/x/net v0.0.0-20220726230323-06994584191e // indirect golang.org/x/sys v0.0.0-20220727055044-e65921a090b8 // indirect golang.org/x/text v0.3.7 // indirect google.golang.org/protobuf v1.28.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) 复制代码
其中 module
是用来定义包名,require
表示定义依赖包及版本,而 indirect
表示间接引用。
go mod 常用命令如下:
- go mod download:下载依赖的module到本地cache(默认为$GOPATH/pkg/mod目录)
- go mod edit:编辑go.mod文件
- go mod graph:打印模块依赖图
- go mod init:初始化当前文件夹, 创建go.mod文件
- go mod tidy:增加缺少的module,删除无用的module
- go mod vendor:将依赖复制到vendor下
- go mod verify:校验依赖
- go mod why:解释为什么需要依赖
使用 Go Modules 创建项目有两种方式,第一种方式是可以直接使用 Goland IDE 选择 Go Modules 模式创建项目。
也可以直接创建一个文件夹作为工作目录,进入文件夹之后使用 go mod init 工作目录名
来初始化,该命令会生成一个 go.mod 文件来管理项目相关依赖。
二、Go Package
包(Package)是多个 Go 源码的集合,是一种高级代码复用方案,Go 语言默认提供了很多包,如 fmt
、os
和 io
等。代码中用到相关包会自动导入。
同变量一样,如果包导入了但是没有使用,IDE 会有报错提示。
包具有如下特性:
- 一个目录下的同级文件归属一个包
- 包名可以与其目录不同名
- 包名为 main 的包为应用程序的入口包,编译源码没有 main 包时将无法编译输出可执行文件。
Go 语言区分到小写,只有变量名或者结构体及结构体字段首字母大写才可以被其他包引用。
Go 中包的导入分为单行和多行导入
import "package1" import "package2" 复制代码
import ( "package1" "package2" ) 复制代码
新建一个 zulu package,首先在该 package 下新建一个 main 文件,接着再新建一个 operator package,在 operator package 下添加两个 add.go 和 sub.go 文件,zulu package 目录结构如下:
. ├── go.mod ├── main.go └── operator ├── add.go ├── go.mod └── sub.go 1 directory, 5 files 复制代码
其中 add.go 和 sub.go 文件的内容如下
// filename: add.go package operator func Add(x, y int) int { return x + y } func addWithlowerCase(x, y int) int { return x + y } 复制代码
// filename:sub.go package operator func Sub(x, y int) int { return x - y } 复制代码
然后我们可以在 main 文件中调用 operator 包下的函数
package main import "zulu/operator" func main() { operator.Add(1, 2) operator.Sub(2, 1) // Unexported function 'addWithlowerCase' usage // operator.addWithlowerCase(1, 2) } 复制代码
如果运行出现 package xxx is not in GOROOT (/usr/local/go/src/xxx)
报错,解决此问题首先要确保是在 Go Mod 模式下进行开发的,既要在 package 目录下执行 go mod init packageName
并且设置 Go 环境变量 GO111MODULE="on"
export GO111MODULE="on" 复制代码
Go Package 的导入可以支持给包名起别名
package main import ( // 起别名 ope "zulu/operator" ) func main(){ // 使用别名调用 ope.Add(1, 2) } 复制代码
如果导入包不使用,为了避免报错可以用 _
命名
package main import ( // 别名为 _ _"zulu/operator" ) func main(){ }