GO学习笔记---Go Module详细使用教程 Vs GOPATH

Go Modules

Go 1.11 引入了新特性,一个新的依赖管理系统。Google 引入了 Go 模块作为GOPATH 的替代方案,用于版本控制和包分发

Go modules(这就是 Go 使用环境变量名称的原因GO111MODULE:表示使用 Go 1.11 模块)。

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

  1. GO111MODULE有三个值:off、on 和 auto(默认值) 在使用模块的时候,GOPATH 是无意义的,不过它还是会把下载的依赖储存在 $GOPATH/src/mod 中,也会把 go install 的结果放在 $GOPATH/bin 中。
    • GO111MODULE=off,无模块支持,go 会从 GOPATH 和 vendor 文件夹寻找包
    • GO111MODULE=on,模块支持,go 会忽略 GOPATH 和 vendor 文件夹,只根据 go.mod 下载依赖
    • GO111MODULE=auto,在 $GOPATH/src 外面且根目录有 go.mod 文件时,开启模块支持
  2. GOPROXY 由于网络监管系统,Go 生态系统中有着许多中国 Gopher 们无法获取的模块,比如最著名的 golang.org/x/...。并且在中国大陆从 GitHub 获取模块的速度也有点慢。因此需要配置GOPROXY来加速Module依赖下载,这里使用goproxy.cn代理,详细介绍:传送门 注: 推荐将 GO111MODULE 设置为on 而不是auto
    • Go 1.13及以上版本 go env -w GOPROXY=https://goproxy.cn,direct
    • Go 1.13以下的版本 export GOPROXY=https://goproxy.cn

Go mod

Golang 1.11 版本引入的 go mod ,其思想类似maven:摒弃vendor和GOPATH,拥抱本地库。从 Go 1.11 开始,Go 允许在 $GOPATH/src 外的任何目录下使用 go.mod 创建项目。在$GOPATH/src中,为了兼容性,Go 命令仍然在旧的 GOPATH 模式下运行。从 Go 1.13 开始,Module模式将成为默认模式。

1.go mod 命令

go mod
The commands are:
  download    download modules to local cache (下载依赖的module到本地cache))
  edit        edit go.mod from tools or scripts (编辑go.mod文件)
  graph       print module requirement graph (打印模块依赖图))
  init        initialize new module in current directory (再当前文件夹下初始化一个新的module, 创建go.mod文件))
  tidy        add missing and remove unused modules (增加丢失的module,去掉未用的module)
  vendor      make vendored copy of dependencies (将依赖复制到vendor下)
  verify      verify dependencies have expected content (校验依赖)
  why         explain why packages or modules are needed (解释为什么需要依赖)

2.新项目

你可以在GOPATH之外创建新的项目

go mod init packagename

可以创建一个空的go.mod,然后你可以在其中增加

require github.com/smallnest/rpcx latest

依赖,或者像上面一样让go自动发现和维护。

go mod download

可以下载所需要的依赖,但是依赖并不是下载到$GOPATH中,而是

$GOPATH/pkg/mod

中,多个项目可以共享缓存的module。

3.老项目

假设你已经有了一个go 项目, 比如在

$GOPATH/src/github.com/smallnest/rpcx

下, 你可以使用

go mod init github.com/smallnest/rpcx

在这个文件夹下创建一个空的go.mod (只有第一行 module github.com/smallnest/rpcx)。 然后你可以通过 go get ./...让它查找依赖,并记录在go.mod文件中(你还可以指定 -tags,这样可以把tags的依赖都查找到)。 通过

go mod tidy

也可以用来为go.mod增加丢失的依赖,删除不需要的依赖,但是我不确定它怎么处理tags。 执行上面的命令会把go.modlatest版本换成实际的最新的版本,并且会生成一个go.sum记录每个依赖库的版本和哈希值。

GO111MODULE:行为

到目前为止,GO111MODULE为每个 Go 操作明确设置了环境变量。无变量集,缺省值GO111MODULEauto,它的行为如下:

go111模块

Golang环境变量

  1. GOROOT:go的安装路径 在~/.bash_profile中添加下面语句配置GOROOT环境变量
    GOROOT=/usr/local/go 
    export GOROOT 
    要执行go命令和go工具, 就要配置go的可执行文件的路径:
    export $PATH:$GOROOT/bin
    注:$PATH windows用;符号分割, mac和类unix用:符号分割
  2. GOPATH: go的工作路径 可以在自己的用户目录下面创建一个目录, 如go
    cd ~ 
    mkdir go
    ~/.bash_profile中添加如下语句:
    export GOPATH=/Users/username/go 
    不要把GOPATH设置成go的安装路径, GOPATH下主要包含三个目录:bin pkg src

    注:Go 1.8 版本之前,GOPATH 环境变量默认是空的;1.8版本之后,默认路径是:$HOME/go

  • src: 存放源代码(比如:.go .c .h .s等)
  • pkg: 编译后生成的文件(比如:.a)
  • bin: 编译后生成的可执行文件, 为了方便,可以把此目录加入到 $PATH 变量中,如果有多个gopath,那么使用${GOPATH//://bin:}/bin添加所有的bin目录


GOPATH

GOPATH 是 Go语言中使用的一个环境变量,它使用绝对路径提供项目的工作目录(Go Workspace)。
例如下面的使用GOPATH 例子

GO111MODULE=off go get github.com/google/go-cmp/cmp
tree -d -L 5 $GOPATH   # assume tree is installed
/go
├── bin
├── pkg
└── src
    └── github.com
        └── google
            └── go-cmp

GO111MODULE=off 表示Go 运行时使用就的GOPATH 模式,而不是Go modules。

因此,go get github.com/google/go-cmp/cmp按照 GOPATH 的模式下载包到$GOPATH/src目录。

GO111MODULE=on go get github.com/google/go-cmp/cmp

tree -d -L 5 $GOPATH
/go
`-- pkg
    |-- mod
    |   |-- cache
    |   |   `-- download
    |   |       |-- github.com
    |   |       |-- golang.org
    |   |       `-- sumdb
    |   `-- github.com
    |       `-- google
    |           `-- go-cmp@v0.5.6
    `-- sumdb
        `-- sum.golang.org

你会发现启用了go modules后的目录结构和没有启用Go modules的目录结构不同。

GOPATH 已经过时了

Go 1.11 is released Go 1.11 is released - go.dev

2018-8-24 发布

提到新的moudules ,是GOPATH的替代方案。modules 提供对版本控制和包分发的支持

在 Go 1.11 之前,所有项目,而不仅仅是依赖包,都必须在$GOPATH目录中。在这里,我尝试在$GOPATH 环境执行

实战:

工作场景:一个没有启用Go moudules,在$GOPATH外面 执行

例如,我在执行一个项目命名testproject,有一个包main有两个文件main.gotest_func.go如下:

main.go:

package main

func main() {
        TestFunc()
}

test_func.go:

package main

import "k8s.io/klog"

func TestFunc() {
        klog.Infoln("Hello Go Modules!")
}

下面运行

#先直接运行,会报错,没有找到对应包
GO111MODULE=off go run .
test_func.go:3:8: cannot find package "k8s.io/klog" in any of:
	/usr/local/go/src/k8s.io/klog (from $GOROOT)
	/Users/YourUserName/go/src/k8s.io/klog (from $GOPATH)

下载对应的包:

/anywhere/outside/gopath/testproject $GO111MODULE=off go get k8s.io/klog
/anywhere/outside/gopath/testproject $GO111MODULE=off go run .
I1201 15:32:25.189443   28174 test_func.go:7] hello go Modules!

不过,确实可以运行,整个项目在$GOPATH 外面。实际上,所有项目都必须在的原因$GOPATH是由于subpackages。一个main包不是这样的,因此它不受此限制的限制。

有问题的场景:Go 有多个包的项目,在外面 $GOPATH

让我们修改它以获得一个子包test

$ tree /anywhere/outside/gopath/testproject
/anywhere/outside/gopath/testproject
├── main.go
└── test
    └── func.go

main.go:

package main
import "test"
func main(){
  test.TestFunc()
}
test/func.go 
package test
  
import "k8s.io/klog"

func TestFunc(){

   klog.Infoln("hello go Modules!")
}
O111MODULE=off go run .
main.go:2:8: cannot find package "test" in any of:
	/usr/local/go/src/test (from $GOROOT)
	/Users/yourUserHome/go/src/test (from $GOPATH)

如果没有启用go modules,我们无法在main package中找到test的这个包,让它工作的唯一办法是,将项目的移动到$GOPATH,

% tree $GOPATH/src/mytest.io/testproject/    
/go/src/mytest.io/testproject/
├── main.go
└── test
    └── func.go

现在我们可以指定test包的路径:mytest.io/testproject/test基于$GOPATH/src. 所以 main.go 可以修改为:

package main
import "mytest.io/testproject/test"
func main(){
  test.TestFunc()
}
运行项目
% GO111MODULE=off go run main.go 
I1201 15:44:39.271735   29038 func.go:7] hello go Modules!

注意main.go在GOPATH外也是没有问题的。主要是子package的目录要在GOPATH下

回到Go modules模式

Go Modules

在$GOPATH外,

/anywhere/outside/gopath/testproject  % go mod init mytest.io/testproject

main.go

package main
  
import "mytest.io/testproject/test"

func main() {
        test.TestFunc()
}

test/func.go

package test
  
import "k8s.io/klog"

func TestFunc(){

   klog.Infoln("hello go Modules!")
}
/anywhere/outside/gopath/% tree testproject 
testproject
├── go.mod
├── go.sum
├── main.go
└── test
    └── func.go

  运行

/anywhere/outside/gopath/testproject % GO111MODULE=on  go run .
I1201 16:01:43.240510   30265 func.go:7] hello go Modules!

如上,我们将项目初始化为 mytest.io/testproject (go mod init mytest.io/testproject)也就是go.mod的目录定义为mytest.io/testproject ,即使在$GOPATH外面,go run 命令搜索,mytest.io/testproject/test ,即项目根目录下面的test子目录搜索包,而不是$GOPATH中。

即搜索

/anywhere/outside/gopath/testproject/test

目录,test/func.go的 package 需要为test 不能为其他的。

参考:

  1.  如何编写 Go 代码(使用 GOPATH)How to Write Go Code (with GOPATH) https://golang.org/doc/gopath_code.html ↩︎

  2. Go 中的版本控制原则 The Principles of Versioning in Go:research!rsc: The Principles of Versioning in Go (Go & Versioning, Part 11) ↩︎

  3. Go 1.13 发布说明 Go 1.13 Release Note:https://golang.org/doc/go1.13#modules ↩︎

     4. Go Module详细使用教程,包管理不在难 - 云+社区 - 腾讯云

     5. Go Modules: an Alternative to GOPATH for Package Distribution | Better Tomorrow with Computer Science

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值