返回介绍

上卷 程序设计

中卷 标准库

下卷 运行时

源码剖析

附录

10.2 模块

发布于 2024-10-12 19:15:50 字数 6975 浏览 0 评论 0 收藏 0

模块 (module)是包(packages)和其依赖项(dependency)的集合。

直接体现是 go.mod 文件,存储了模块路径、编译器版本,以及依赖项列表。

如此,模块是依赖管理方式,是发布和版本控制单元。

module = go.mod + package + subs...
  • 模块路径(module path):在 go.mod 中声明的名称标识。
  • 根目录(module root directory):包含 go.mod 文件的目录。
  • 主模块(main module):执行 go 命令时,所在目录对应的模块。

初始化

模块对应一个包含 go.mod 的源码目录,所有不含 go.mod 的子目录都是其成员。

  test/
    |
    +-- go.mod        (github.com/qyuhen/test)
    |
    +-- main.go
    |
    +-- mylib/        (github.com/qyuhen/test/mylib)
          |
          +-- add.go
$ cd test

$ go mod init github.com/qyuhen/test
go: creating new go.mod: module github.com/qyuhen/test
$ cd test/mylib

$ go list -m                     # 向外查找 go.mod,主模块。
github.com/qyuhen/test

模块路径描述了线上存储位置,通过 go get 下载到本地缓存目录。

import 导入模块时,使用模块路径而非本地路径。

// go.mod

module github.com/qyuhen/test    // 模块路径

go 1.18                          // 编译器最低版本号
// main.go

package main

import (
    // "test/mylib"
    //  ~~~~~~~~~~ package test/mylib is not in GOROOT
    
	"github.com/qyuhen/test/mylib"
)

func main() {
	println(mylib.Add(1, 22))
}

如果子目录包含 go.mod ,那么它将是独立模块,不再属于当前模块。

$ cd test/mylib

$ go mod init github.com/qyuhen/mylib
go: creating new go.mod: module github.com/qyuhen/mylib

$ cd ..

$ go build
no required module provides package github.com/qyuhen/test/mylib; 
to add it: go get github.com/qyuhen/test/mylib

依赖管理

命令 go get 添加、下载(更新)依赖项,其他操作可用 go mod 完成。

  • GOPROXY 下载源码到本地缓存 GOMODCACHE 目录。
  • go.modgo.sum 添加依赖项和验证信息。
  • 使用 go clean -modcache 清除缓存。(自动重新下载)
$ go get .                        # 分析源码,添加所有依赖。
$ go get example.com/my           # 指定模块,下载最新版本。

$ go get example.com/my@v1.3.4    # 指定版本号。
$ go get example.com/my@lastet    # 最新版本。

$ go get example.com/my@4cf76c2   # 伪版本号(commit hash)
$ go get example.com/my@bufix     # 分支(branch)

go mod 管理模块。

  • init : 初始化模块,创建 go.mod 文件。
  • tidy : 添加遗漏,移除不需要的依赖项。
  • edit : 命令行方式编辑模块设置。
  • -fmt :格式化 go.mod 文件。
  • -module :模块路径。
  • -go :编译器版本。
  • -require , -droprequire :添加直接或间接依赖项。
  • -replace, -dropreplace :替换模块路径或版本。
  • -exclude , -dropexclude :排除模块或版本。
  • -retract , -dropretract :标识有问题需要忽略的版本。
$ go mod edit -require example.com/my@v1.3.4

版本标识

版本标识模块不可变快照。

  • v 开头,然后是语义版本(semantic version)。
  • 不兼容(incompatible)更新,递增主要版本号。
  • 添加功能的兼容更新,递增次要版本号。
  • 优化和修复缺陷,不影响导出接口,递增补丁版本号。
  • 正式发布前的预发行版本,添加 -pre 后缀。
  • 使用 git tag 之类的功能标记语义化版本号。
  • 如没有标记,则使用提交(commit)信息(time, ident)构成伪版本号。
v(major).(minor).(patch)-(pre|beta)

  主要     次要     补丁    预发行或测试版
v1.2.3
v1.2.3-pre
v1.5.0-beta

v0.0.0-20191109021931-daa7c04131f5 --> go get example.com/my@daa7c041

查看所有版本。

$ go list -m -versions github.com/shirou/gopsutil

v2.0.0+incompatible 
v2.16.10+incompatible 
v2.16.11+incompatible ...
v2.21.11+incompatible 
v3.20.10+incompatible ... 
v3.21.11+incompatible
$ go list -m -versions all   

更新依赖项。

$ go get -u example.com/my@v1.3          # minor or patch releases
$ go get -u=patch example.com/my@v1.3.4  # patch release

可使用 >>=<<= 操作符指定版本查询范围(module query)。

选择最接近条件的版本。例如: >=1.0 选择 1.0<1.0 选择 0.9 ,而不是 0.8

注意,命令行添加引号,否则显示版本错误。

$ go get "github.com/shirou/gopsutil@>v2.16.10"

兼容性规则

如新版和旧版有相同导入路径,则必须保证向后兼容(backwards compatible)。

主版本号出现在模块路径尾部,表示重大不兼容更新。

mod/v2mod/v1 不兼容。

v0v1 不需要使用版本后缀。

v0 本身就表示不稳定且不具有兼容性保证, v1 为默认版本。

另外,有预发行后缀也表示该版本不稳定,不受兼容性约束。

导入语句(import)须使用包含版本号( v2 )的全路径。

通常建议在原模块下建立 /v2/go.mod 模块(子目录)。

import github.com/qyuhen/test/v2

工作空间

以工作空间(workspace)解决多模块开发遇到的问题。

  • 编译时,找不到未发布模块(非子包)。
  • 只能以 replace 将模块路径替换为本地路径。
  • 污染的 go.mod 意外提交到代码仓库。
   app/                  (workspace)
    |
    +-- go.work
    |
    +-- test/            (github.com/qyuhen/test)
    |    |
    |    +-- go.mod
    |    |
    |    +-- main.go
    |
    +-- mylib/           (github.com/qyuhen/mylib)
         |
         +-- go.mod
         |
         +-- add.go
$ go work init                   # 初始化工作空间。
$ go work use ./test ./mylib     # 添加模块。
// go.work

go 1.18

use (
    ./mylib
    ./test
)

导入(import)工作空间内其他模块,无需 require 指令。

// mylib/go.mod

module github.com/qyuhen/mylib

go 1.18
// test/go.mod

module github.com/qyuhen/test

go 1.18

// require github.com/qyuhen/mylib v0.0.1   // 不需要 !!!
// test/main.go

package main

import (
	"github.com/qyuhen/mylib"
)

func main() {
	println(mylib.Add(11, 22))
}

若必须添加 require ,编译时可关闭 GOPROXY ,阻止在线获取模块验证信息。

$ GOPROXY=off go build

模块还可放在空间目录外,或加入多个工作空间。

// go.work

go 1.18

use (
	../mylib
	./test
)

环境变量

模块感知(module-aware)模式,相关环境变量说明。

  • GO111MODULE :模块感知模式开关。(默认:on)
  • GOMODCACHE :模块缓存路径。
  • GOPROXY :模块代理服务列表。
  • GOSUMDB :模块数据安全校验数据库。
  • GOPRIVATE :私有模块路径,绕过 GOPROXY 直接获取。

GOPRIVATE=*.example.com ,以逗号分隔多个地址。

GOPRIVATEGONOPROXYGONOSUMDB 的默认值。

离线编译

打包含依赖在内的所有源码,进行离线编译。

$ go mod vendor                    # 将依赖复制到 ./vendor 目录下。
$ GOWORK=off go build -mod vendor  # 禁用工作空间,以 vendor 方式编译。

Go Modules Reference ( go.mod )

Managing Dependencies

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文