如果想在 V2EX 获得更好的推广效果,欢迎了解 PRO 会员机制:
https://www.v2ex.com/pro/about

如果你经常使用铜币置顶主题,持有 V2EX Solana Token 会在每日签到时获得额外铜币:
https://www.v2ex.com/solana
haicoderibai
V2EX  ›  推广

一文搞懂 Go Mod

  •  
  •   haicoderibai · Oct 28, 2020 · 1825 views
    This topic created in 2048 days ago, the information mentioned may be changed or developed.

    Go Mod

    Go Mod 包管理教程

    随着 go 1.11 的发布,go 官方引入了 go module 来解决依赖管理问题,go module 被集成到原生的 go cmd 中。

    但是如果你的代码库在 $GOPATH 中,go1.11 的 module 功能是默认不会开启的,想要开启也非常简单,通过一个环境变量即可开启 go module:

    export GO111MODULE=on
    

    Go Mod 与 GoPath

    现在 modules 机制仍在早期阶段,所以 golang 提供了一个环境变量 “GO111MODULE”,默认值为 auto 。

    如果当前目录里有 go.mod 文件,就使用 go modules,否则使用旧的 GOPATH 和 vendor 机制,因为在 modules 机制下 go get 只会下载 go modules,这一行为会在以后版本中成为默认值,这里我们保持 auto 即可,如果你想直接使用 modules 而不需要从 GOPATH 过度,那么把 “GO111MODULE” 设置为 on 。

    modules 和传统的 GOPATH 不同,不需要包含例如 src,bin 这样的子目录,一个源代码目录甚至是空目录都可以作为 module,只要其中包含有 go.mod 文件。

    关于$GOPROXY

    使用

    当我们使用 go 的时候,go 默认会直接从代码库中去下载所需的相关依赖,GOPROXY 这个环境变量可以让我们控制自己从哪里去下载源代码

    如果 GOPROXY 没有设置,go 会直接从代码库下载相关依赖代码。如果你像下面这样设置了这个环境变量,那么你就会通过 goproxy.io 下载所有的源代码,设置 proxy 的命令如下:

    export GOPROXY=https://goproxy.io
    

    你可以通过置空这个环境变量来关闭 proxy,命令如下:

    export GOPROXY=
    

    原理

    以前执行 go get golang.org/x/net 时,那么 net 代码库会下载到本地 GOPATH 中,以后有任何项目引用到了 golang.org/x/net 都不会再去下载这个代码库,因为本地 GOPATH 已经有了,哪怕版本不对,golang 也会引用。

    但是随着 module 概念引入 go 语言,每个引入的 module 拥有了 version 。随着代码库的不断更新迭代,大家即使是对同一个代码库的引用也可能用了不同的 tag 或者 commit hash,基于这个现状,go1.11 的 module 会比以前更频繁的下载源代码。

    但是基于中国有中国特色的互联网,我们有时候很难 get 到我们需要的依赖源代码,进而导致项目编译失败,CI 失败。于是,我们需要一个 proxy 。

    代理设置

    代理地址

    主要有两个地址,如下:

    https://goproxy.io
    https://athens.azurefd.net
    

    以上两个地址,可以根据个人喜好随意选择。

    设置方法

    Windows

    $env:GOPROXY = "https://goproxy.io"
    

    Linux

    export GOPROXY=https://goproxy.io
    

    Go Mod 使用

    go module 的初始化

    我们首先,创建一个空的项目文件夹

    E:\Code\gomod
    

    接着,我们进行项目初始化:

    #Linux
    export GO111MODULE=on
    export GOPROXY=https://goproxy.io
    
    #Windows
    $env:GO111MODULE=on
    $env:GOPROXY="https://goproxy.io"
    
    go mod init [module name]
    

    初始完成后会在目录下生成一个 go.mod 文件,里面的内容只有一行 “module test”。

    包管理

    当我们使用 go build,go test 以及 go list 时,go 会自动得更新 go.mod 文件,将依赖关系写入其中。如果你想手动处理依赖关系,那么使用如下的命令:

    go mod tidy
    

    这条命令会自动更新依赖关系,并且将包下载放入 cache 。

    Go Mod 常用命令

    go.mod 文件命令

    go.mod 提供了 module 、require 、replace 和 exclude 四个命令,如下:

    | 命令 | 描述 | | --------- | ------------------------ | | module | 语句指定包的名字(路径) | | require | 语句指定的依赖项模块 | | replace | 语句可以替换依赖项模块 | | exclude | 语句可以忽略依赖项模块 |

    go mod 常用命令

    | 命令 | 描述 | | ---------- | ------------------------------------------------------------ | | download | 下载模块到本地缓存,具体可以通过命令 go env 查看,其中环境变量 GOCACHE 就是缓存的地址,如果该文件夹的内容太大,可以通过命令 go clean -cache | | edit | 从工具或脚本中编辑 go.mod 文件 | | graph | 打印模块需求图 | | init | 在当前目录下初始化新的模块 | | tidy | 添加缺失的模块以及移除无用的模块 | | verify | 验证依赖项是否达到预期的目的 | | why | 解释为什么需要包或模块 |

    Go Mod 案例

    引用第三方库

    我们首先,在 E:\Code\gomod 创建 main.go 文件,并输出以下内容:

    package main
        
        import (
        	"context"
        	"log"
        	"time"
        
        	"github.com/chromedp/chromedp"
        )
        
        func main() {
        	// create chrome instance
        	ctx, cancel := chromedp.NewContext(
        		context.Background(),
        		chromedp.WithLogf(log.Printf),
        	)
        	defer cancel()
        
        	// create a timeout
        	ctx, cancel = context.WithTimeout(ctx, 15*time.Second)
        	defer cancel()
        
        	// navigate to a page, wait for an element, click
        	var example string
        	err := chromedp.Run(ctx,
        		chromedp.Navigate(`https://golang.org/pkg/time/`),
        		// wait for footer element is visible (ie, page is loaded)
        		chromedp.WaitVisible(`#footer`),
        		// find and click "Expand All" link
        		chromedp.Click(`#pkg-examples > div`, chromedp.NodeVisible),
        		// retrieve the value of the textarea
        		chromedp.Value(`#example_After .play .input textarea`, &example),
        	)
        	if err != nil {
        		log.Fatal(err)
        	}
        	log.Printf("Go's time.After example:\n%s", example)
        }
    

    接着,我们开始下载包,输入以下命令:

    go mod tidy
    

    接着,我们可以发现,go.mod 和 go.sum 都增加了包的依赖文件。现在,我们就可以直接进行编译,输入以下命令:

    go build
    

    引用自定义库

    我们首先创建如下目录:

    E:\Code\wolferserver
    E:\Code\wolferserver\base
    E:\Code\wolferserver\base\configs
    
    E:\Code\wolferserver\src
    E:\Code\wolferserver\src\logicserver
    

    接着,我们再创建如下文件:

    E:\Code\wolferserver\base\configs\configs.go
    E:\Code\wolferserver\src\logicserver\main.go
    

    每个文件的文件内容如下:

    //configs.go
    package configs
    
    import "fmt"
    
    func Demo(){
    	fmt.Println("Hello Demo")
    }
        
        
    //main.go
    package main
    
    import (
    	"github.com/gin-gonic/gin"
    	"wolferserver/base/configs"
    )
    
    func main(){
    	logInit()
    }
    
    func logInit() {
    	configs.Demo()
    
    	gin.New()
    }
    

    最后,我们直接输入以下命令,就可以运行我们的程序:

    go run src/lpgicserver/main.go
    

    版本控制

    包管理的另外一项重要功能就是包的版本控制。modules 同样可以做到。

    go.sum

    github.com/chromedp/cdproto v0.0.0-20190429085128-1aa4f57ff2a9 h1:ARnDd2vEk91rLNra8yk1hF40H8z+1HrD6juNpe7FsI0=
    

    前面部分是包的名字,也就是 import 时需要写的部分,而空格之后的是版本号,版本号遵循 “版本号+时间戳+hash”。

    我们自己指定版本时只需要制定版本号即可,没有版本 tag 的则需要找到对应 commit 的时间和 hash 值。默认使用最新版本的 package 。

    更改版本

    现在我们要修改依赖关系了,我们想使用 chromedp 的 v0.1.0 版本,只需要如下命令

    go mod edit -require="github.com/chromedp/[email protected]"
    

    @ 后面加上你需要的版本号。go.mod 已经修改了。我们还需要让 go modules 更新依赖关系,这里我们手动 go mod tidy 即可。

    查看更多文章,请关注公众号:

    嗨客网(www.haicoder.net)

    No Comments Yet
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   3752 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 47ms · UTC 04:34 · PVG 12:34 · LAX 21:34 · JFK 00:34
    ♥ Do have faith in what you're doing.