惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
DataBreaches.Net
S
Schneier on Security
T
The Exploit Database - CXSecurity.com
Webroot Blog
Webroot Blog
AI
AI
P
Palo Alto Networks Blog
Attack and Defense Labs
Attack and Defense Labs
WordPress大学
WordPress大学
月光博客
月光博客
阮一峰的网络日志
阮一峰的网络日志
Spread Privacy
Spread Privacy
T
Tor Project blog
罗磊的独立博客
小众软件
小众软件
S
Security Affairs
酷 壳 – CoolShell
酷 壳 – CoolShell
量子位
Apple Machine Learning Research
Apple Machine Learning Research
T
Threatpost
NISL@THU
NISL@THU
博客园_首页
PCI Perspectives
PCI Perspectives
大猫的无限游戏
大猫的无限游戏
IT之家
IT之家
N
News and Events Feed by Topic
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Forbes - Security
Forbes - Security
博客园 - 叶小钗
D
Darknet – Hacking Tools, Hacker News & Cyber Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Last Week in AI
Last Week in AI
L
LINUX DO - 热门话题
T
Threat Research - Cisco Blogs
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
腾讯CDC
Security Latest
Security Latest
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
The Cloudflare Blog
A
About on SuperTechFans
爱范儿
爱范儿
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
TaoSecurity Blog
TaoSecurity Blog
宝玉的分享
宝玉的分享
G
GRAHAM CLULEY
雷峰网
雷峰网
F
Full Disclosure
I
Intezer
Cloudbric
Cloudbric
博客园 - 三生石上(FineUI控件)
U
Unit 42

文章列表 on polarisxu

通过一个例子让你彻底掌握 Go 工作区模式 这道题正确率竟然只有 22% Go 开源项目推荐:一个简单的 Go 练手项目 go test 如何禁用缓存? Go1.18 快讯:constraints 包被移除标准库 跟着 Go 作者学泛型 「2022 版」轻松搞定 Go 开发环境 鹅厂小哥用行动反对加班:程序员加班能被终结吗? Go 为什么选择 Gopher 作为吉祥物? 本地如何配置多个 GitHub/Gitee 账号? 为 Java 开发者准备的 Go 教程 02:Java 有而 Go 无 GitHub 发现了 studygolang 项目依赖的漏洞 Typora 宣布收费后,这款开源 Markdown 编辑器火了 为 Java 开发者准备的 Go 教程 01:漫游了 我的 2021 年终总结 泛型版 singleflight:Go 中如何防止缓存击穿? 2021 年你写了多少代码?这个 Go 工具帮你统计 Go1.18 新特性:TryLock Go 泛型入门教程 程序员瑞士军刀:各种结构的转换工具 终于有 Go 版的 Elasticsearch 了 Go泛型系列:maps 包讲解 Go 1.18 中的 any 是什么? Go1.18 快讯:新的 IP 包 Go编程模式:详解函数式选项模式 Go泛型系列:slices 包讲解 Nginx 竟然也有 playground — Go 语言构建的 Go泛型系列:Go1.18 类型约束那些事 Go1.18 快讯:Module 工作区模式 Go1.18 快讯:新增的 Cut 函数太方便了 Go1.18 快讯:废弃了这个 API Go1.18 快讯:新增字符串 Clone API Go:如何获得项目根目录? Go 如何获取和设置环境变量 重磅变动:更快找到微信公众号里的Go文章 Go 这样设置版本号:我们的项目也可以 假期结束,推荐 2 本 manning 出的 Go 图书 Go Fiber 框架系列教程 04:测试应用 Go Fiber 框架系列教程 03:中间件 Go泛型系列:提前掌握Go泛型的基本使用 推荐一个 Go GUI 实战项目 Go Fiber 框架系列教程 02:详解相关 API 的使用 Go Fiber 框架系列教程 01: 和 Express 对比学习 Go Module:私有不合规库怎么解决引用问题 Go1.17 新特性:go get 变了 Go1.17 新特性:testing 包的相关变化 StackOverflow 上关于 Go select 死锁的问题 新书推荐:用 Gin 框架构建分布式应用 Go 官网要变天。。。 Gin 这是要成为 Go 官方框架? 扬眉吐气:刚刚,Go 已经默认支持泛型了 Go 第三方库推荐:类型转换如此简单 担心密码提交到 GitHub?建议使用这个 Go 开源工具 Go 的时间格式化为什么是 2006-01-02 15:04:05? GitHub 为 Go 社区带来安全支持 Go开源项目推荐:500行代码确认请求时间花在哪 一道关于 len 函数的诡异 Go 面试题解析 厉害了我的 Go:推荐系统都有开源实现 Go1.17 新特性:新版构建约束 这个工具真好:看看你的Go项目依赖有无漏洞 网友很强大,发现了Go并发下载的Bug Rust 劝退系列 09:函数 Go项目实战:一步步构建一个并发文件下载器 这本 Go 新书挺期待的:100 个常见错误 Go 启用新的官方问答社区 这是要干嘛?!微软招 Go 编译器全职开发人员 Go1.17 快报之标准库越来越注重易用性 Go1.17 新特性之切片变数组 回顾 Go 官网的演变史 站长8年前的Go代码竟然进入大厂的项目里了 Go图书翻译:一个好消息,一个坏消息 不怕烂尾!决定组织翻译这本 Go 图书 Rust 劝退系列 08:模式匹配 一本花了2.5年写成的Go免费在线图书 被黑惨了:一句话,说明自己会 Go,咋整? Go1.16 中的新函数 signal.NotifyContext 怎么用? Go 1.17 新特性提前学之测试执行随机化 Rust 劝退系列 07:流程控制 官方的 Go 多版本管理:使用和原理 Rust新书:给你一个劝退的理由 周刊题解:常量表达式这个规则应该了解下 盘点那些使用 Go 语言的国外公司 编写了50万行Go代码是一种什么体验 Rust 劝退系列 06:常量 Uber 使用 Go 的规模这么大?!都自己定制的 Go 编译器了 Go Team Leader — rsc 大神新开源了一个库,增强模板功能 再一次看到了 Go 的节制:int128 类型要不要支持? Rust 劝退系列 05:复合数据类型 「卷」有理论依据:海勒姆定律—Go又是怎么卷的 Go 真的也可以进行 GUI 开发:还有这样的图书呢 Rust 劝退系列 04:基本数据类型 我的 Go 语言书单 Rust 劝退系列 03:变量 我又来推荐免费 Go 新书了:一本用 Go 讲架构的书 注释竟然还有特殊用途?一文解惑 //go:linkname 指令 这个功能,公众号、微信群会不会被玩坏? 一道 Go 闭包题,面试官说原来自己答错了:面别人也涨知识 Rust 劝退系列 02:第一个 Rust 程序 Rust 劝退系列 01:打造开发环境 答应我,这次一定彻底搞懂 Go 中的类型别名
Go 1.17 新特性:Module 有哪些变化?
2021-08-21 · via 文章列表 on polarisxu

大家好,我是 polarisxu。

自从 Go1.11 增加 Go Module 以来,每个版本都在不断改进 Module。Go1.17 也不例外。这次最主要的变化有两点:

  • Module graph pruning:Module 依赖图修剪
  • Lazy Loading:Module 延迟加载

此外还有 Deprecated 注释等。本文就一起探究下这些新变化,因为有人没看懂,不知道这些变化是什么意思。

要搞懂这个知识点,需要对比 1.17 之前的情况。

注意,这个变化并不会影响 go mod 的任何使用

为了方便演示,我们构建一个这样的例子。

有四个模块:主模块(studymod)和 a、b、c 三个模块,如下图:

module studymod 是我们的项目,它依赖模块 a 中的 x 包,而 x 包依赖模块 b,同时 a 包中的 y 包依赖模块 c。

很显然,对我们的项目 studymod 来说,模块 c 的代码根本没用上。Go 1.17 对 module 的改进主要就是在这种没用上的模块上。

基于 Go1.16

假定在 $HOME 下创建一个新目录 gomod116,构建如下目录结构:

[xuxinhua@/Users/xuxinhua/gomod116]
$ tree -L 3
.
├── a
│   ├── x
│   │   └── x.go	// 包含正确的包定义和 import
│   └── y
│       └── y.go
├── b
│   └── b.go
├── c
│   └── c.go
└── studymod.go

在 Go 文件中只是简单的定义包和 import。几个 go 文件的内容分别如下:

// x.go
package x

import _ "b"

// y.go
package y

import _ "c"

// b.go
package b

// c.go
package c

// studymod.go
package studymod

import _ "a/x"

进入 gomod116 目录,将 Go 版本切换到 Go1.16.x(多版本发挥作用了,多版本问题,可以看看这篇文章:终于找到了一款我喜欢的安装和管理 Go 版本的工具 ),然后执行下列命令:

$ go mod init studymod
$ cd a
$ go mod init a
$ cd ../b
$ go mod init b
$ cd ../c
$ go mod init c

因为模块 a 依赖模块 b 和 c,往 a/go.mod 增加如下代码:

module a

go 1.16

require (
    b v0.1.0
    c v0.1.0
)

在 gomod116 根目录的 go.mod 增加如下代码:

module studymod

go 1.16

require a v0.1.0

replace (
        a v0.1.0 => ./a
        b v0.1.0 => ./b
        c v0.1.0 => ./c
)

因为 studymod 只直接依赖模块 a。replace 部分可以忽略,只是为了本地能够正常引入模块。

此时,在 gomod116 目录下执行 go build,如果不报错,表示一切正常,我们可以执行如下命令看到依赖关系:

$ go mod graph
studymod a@v0.1.0
a@v0.1.0 b@v0.1.0
a@v0.1.0 c@v0.1.0

studymod 依赖 a,a 依赖 b 和 c。

但我们知道,studymod 模块实际根本不需要模块 c,因此,我们尝试在 studymod 模块中删除模块 c 的引用,即删除 go.mod 中 replace 部分的 c v0.1.0 => ./c,再次执行 go build:

$ go build
go: a@v0.1.0 requires
	c@v0.1.0: missing go.sum entry; to add it:
	go mod download c

可见模块 c 不能少。(验证后,记得将 go.mod 恢复原样)

基于 Go1.17

现在我们基于 Go1.17 做类似的验证,将 Go 切到 1.17,执行如下命令,将 gomod116 拷贝一份:

$ cp -rf gomod116 gomod117

然后进入 gomod117 目录,将 go.mod 的 版本由 1.16 改为 1.17:

module studymod

go 1.17

require a v0.1.0

replace (
    a v0.1.0 => ./a
    b v0.1.0 => ./b
    c v0.1.0 => ./c
)

接着执行 go mod tidy,发现 go.mod 变成这样:

module studymod

go 1.17

require a v0.1.0

require b v0.1.0 // indirect

replace (
        a v0.1.0 => ./a
        b v0.1.0 => ./b
        c v0.1.0 => ./c
)

多了一行 require,记录了 module studymod 的间接依赖:module b@v0.1.0。执行 go build 一切正常。

跟 Go1.16 一样,删除掉 c v0.1.0 => ./c 这行,再次执行 go build,依然正常。这就是依赖图裁剪,再看依赖关系,跟 Go1.16 是不一样的。

$ go mod graph
studymod a@v0.1.0
studymod b@v0.1.0
a@v0.1.0 b@v0.1.0
a@v0.1.0 c@v0.1.0

这么做的优劣

这么做是基于社区的反馈,有兴趣的可以看看这个提案:Proposal: Lazy Module Loading ,这也是合理的,毕竟没有用到的代码为什么一定需要呢?

此外,裁剪后,go.mod 中会包含入更多的依赖项(完整的依赖列表),新包含的依赖项单独放在一个 require 下。可以通过 https://github.com/studygolang/studygolang 试验下。下载该代码后,执行如下命令:

diff 后,在原来的基础上多出了如下的 require:

有点类似其他语言中 xxx.lock 文件的感觉了。

当然,这种方式后,go.mod 的文件会更大,这也是该方式的一个相对劣势。

02 延迟加载(lazy Loading)

理解了上面依赖图的裁剪,延迟加载就一句话:那些根本没有用上的模块(比如上面例子中的模块 c),Go 1.17 后,Go 命令不会去读取其 go.mod 文件。如果之后需要了,再去加载。

03 Deprecated 注释

Go1.17 go.mod 中支持 Deprecated 注释,用来标明该模块废弃了。

// Deprecated: use example.com/mod/v2 instead.
module example.com/mod

对于那些使用了被废弃的 module 的 go 项目,go list、go get 命令都会给出 warning。

看过我这篇文章:《从 go-chi 框架撤回所有主版本聊 Go1.16 的新特性》 的朋友,可能会有疑问,撤回和废弃有何不同,如何分别使用?这里稍微总结下:

撤回的使用场景

  • 发现了一个严重的安全漏洞;
  • 发现了严重的不兼容性或 bug;
  • 这个版本是偶然发布的,或是过早发布了;

而 Deprecated 是用来作废整个 module 的,也就是说,不能废弃某个 minor 或 patch 版本。Deprecated 更多用来提示使用者升级到更新的 major 版本,比如要废弃 v1,希望大家升级到 v2,就应该使用 Deprecated。

04 总结

还有其他一些小的变动,这里不一一列举。提醒下大家,从 Go1.16 版本开始,下载安装 Go 二进制程序,不再使用 go get,而是 go install,go get 只用来下载普通包。

因为 module 越来越完善,官方针对 module 也有更完整的文档:https://docs.studygolang.com/ref/mod