Go 博客
Go 1.16 中的新模块变化
我们希望您喜欢 Go 1.16!这个版本有很多新特性,特别是关于模块的。发行说明 简要描述了这些变化,但让我们深入探讨其中几个。
模块默认开启
现在,go
命令默认在模块感知模式下构建软件包,即使不存在 go.mod
文件也是如此。这是朝着在所有项目中使用模块迈出的重要一步。
通过将 GO111MODULE
环境变量设置为 off
,仍然可以在 GOPATH 模式下构建软件包。您也可以将 GO111MODULE
设置为 auto
,以便仅在当前目录或任何父目录中存在 go.mod 文件时启用模块感知模式。这之前是默认设置。请注意,您可以使用 go env -w
永久设置 GO111MODULE
和其他变量。
go env -w GO111MODULE=auto
我们计划在 Go 1.17 中放弃对 GOPATH 模式的支持。换句话说,Go 1.17 将忽略 GO111MODULE
。如果您有项目尚未在模块感知模式下构建,现在是迁移的时候了。如果存在阻止您迁移的问题,请考虑提交一个 issue 或一份 体验报告。
go.mod 和 go.sum 不再自动更改
以前,当 go
命令发现 go.mod
或 go.sum
中存在问题(例如缺失的 require
指令或缺失的 checksum)时,它会尝试自动修复问题。我们收到了很多反馈,认为这种行为令人意外,特别是对于像 go list
这样通常没有副作用的命令。自动修复并不总是理想的:如果导入的软件包未由任何所需的模块提供,go
命令会添加一个新的依赖项,这可能会触发常用依赖项的升级。即使是拼写错误的导入路径也会导致(失败的)网络查找。
在 Go 1.16 中,模块感知命令在发现 go.mod
或 go.sum
中的问题后会报告错误,而不是尝试自动修复。在大多数情况下,错误消息会建议一个命令来修复问题。
$ go build
example.go:3:8: no required module provides package golang.org/x/net/html; to add it:
go get golang.org/x/net/html
$ go get golang.org/x/net/html
$ go build
与以前一样,如果存在 vendor
目录,go
命令可能会使用它(详情请参阅 Vendoring)。像 go get
和 go mod tidy
这样的命令仍然会修改 go.mod
和 go.sum
,因为它们的主要目的是管理依赖项。
安装指定版本的可执行文件
现在,go install
命令可以通过指定 @version
后缀来安装特定版本的可执行文件。
go install golang.org/x/tools/gopls@v0.6.5
使用此语法时,go install
将安装来自该确切模块版本的命令,忽略当前目录和父目录中的任何 go.mod
文件。(如果没有 @version
后缀,go install
会像往常一样继续操作,使用当前模块的 go.mod
中列出的版本要求和替换来构建程序。)
我们过去推荐使用 go get -u program
来安装可执行文件,但这种用法与 go get
在 go.mod
中添加或更改模块版本要求的含义混淆太多。为了避免意外修改 go.mod
,人们开始建议使用更复杂的命令,例如
cd $HOME; GO111MODULE=on go get program@latest
现在我们都可以改为使用 go install program@latest
。有关详情,请参阅 go install
。
现在我们都可以改用 go install program@latest
。详情请参阅 go install
。
为了消除关于使用哪个版本的歧义,在使用此安装语法时,程序 go.mod
文件中允许存在的指令有一些限制。特别是,目前不允许使用 replace
和 exclude
指令。从长远来看,一旦新的 go install program@version
在足够多的用例中运行良好,我们计划让 go get
停止安装命令二进制文件。详情请参阅 issue 43684。
模块撤回
您是否曾不小心在模块版本尚未准备好之前发布了它?或者在发布某个版本后立即发现了需要快速修复的问题?已发布的版本中的错误很难纠正。为了保持模块构建的确定性,版本发布后不能修改。即使您删除或更改版本标签,proxy.golang.org
和其他代理很可能已经缓存了原始版本。
模块作者现在可以使用 go.mod
中的 retract
指令来 撤回 模块版本。被撤回的版本仍然存在且可以下载(因此依赖它的构建不会中断),但 go
命令在解析像 @latest
这样的版本时不会自动选择它。go get
和 go list -m -u
会打印关于现有使用的警告。
// Remote-triggered crash in package foo. See CVE-2021-01234.
retract v1.0.5
例如,假设流行库 example.com/lib
的作者发布了 v1.0.5
,然后发现了一个新的安全问题。他们可以在其 go.mod
文件中添加一个指令,如下所示
$ go list -m -u all
example.com/lib v1.0.0 (retracted)
$ go get .
go: warning: example.com/lib@v1.0.5: retracted by module author:
Remote-triggered crash in package foo. See CVE-2021-01234.
go: to switch to the latest unretracted version, run:
go get example.com/lib@latest
对于交互式的、基于浏览器的指南,请查看 撤回模块版本(位于 play-with-go.dev 网站)。有关语法详情,请参阅 retract
指令文档。
接下来,作者可以标记并推送版本 v1.0.6
,这是新的最高版本。在此之后,已经依赖于 v1.0.5
的用户在检查更新或升级依赖包时会收到撤回的通知。通知消息可能包含 retract
指令上方注释中的文本。
对于交互式的、基于浏览器的指南,请查看 play-with-go.dev 上的撤回模块版本。有关语法详情,请参阅 retract
指令文档。
使用 GOVCS 控制版本控制工具
go
命令可以从像 proxy.golang.org 这样的镜像或直接使用 git
、hg
、svn
、bzr
或 fossil
从版本控制仓库下载模块源代码。直接访问版本控制非常重要,特别是对于在代理上不可用的私有模块,但它也可能是一个安全问题:版本控制工具中的错误可能被恶意服务器利用来运行非预期的代码。
GOVCS=github.com:git,evil.com:off,*:git|hg
Go 1.16 引入了一个新的配置变量 GOVCS
,它允许用户指定哪些模块允许使用特定的版本控制工具。GOVCS
接受一个逗号分隔的 pattern:vcslist
规则列表。pattern
是一个 path.Match
模式,匹配模块路径的一个或多个前导元素。特殊模式 public
和 private
分别匹配公共模块和私有模块(private
定义为与 GOPRIVATE
中的模式匹配的模块;public
是其他所有模块)。vcslist
是允许的版本控制命令的管道分隔列表,或者关键字 all
或 off
。
例如
GOVCS=public:git|hg,private:all
有关详情,请参阅 使用 GOVCS
控制版本控制工具。
通过此设置,路径位于 github.com
的模块可以使用 git
下载;路径位于 evil.com
的模块不能使用任何版本控制命令下载;所有其他路径(*
匹配所有)可以使用 git
或 hg
下载。
如果未设置 GOVCS
,或者模块不匹配任何模式,go
命令将使用此默认设置:允许公共模块使用 git
和 hg
,允许私有模块使用所有工具。仅允许 Git 和 Mercurial 的理由是,这两个系统作为不受信任服务器的客户端运行时,其安全性问题受到了最多的关注。相比之下,Bazaar、Fossil 和 Subversion 主要用于受信任、经过身份验证的环境,并且作为攻击面的审查不够充分。也就是说,默认设置是
下一篇文章:上下文和结构体
详情请参阅 使用 GOVCS
控制版本控制工具。
接下来是什么?