请教一个问题,一个 go1.17 的库要怎么测试泛型是否正常工作?

2022-07-09 15:53:34 +08:00
 Trim21

最近写了个 golang 的库,我没有用到泛型也不需要泛型,所以就在 go.mod 里面写了 go 1.17

但是因为用到了 unsafereflect 这些直接操作了内存,所以有必要测试一下 1.18 的泛型能不能正常工作。

但是因为我在 go.mod 里面写的版本要求是 1.17 ,所以不能使用泛型语法。 //go:build go1.18 之类的条件编译也不能解决这个问题,因为 go.mod 里面写的还是 1.17 ,所以就算泛型测试在 go1.18 下才会运行,还是不能用泛型语法。

难道只能额外加一个文件夹,额外写一个 go.mod 用 replace 指向我的库的位置,然后用在 ci 里用多个 go 版本跑我的库的测试和这个额外的文件夹里的 go1.18 测试?

2148 次点击
所在节点    Go 编程语言
19 条回复
pastor
2022-07-09 16:07:33 +08:00
go 向后兼容,比如 1.18 的 go 兼容 1.17 及更低版本的 go 的代码,并不是说 mod 里你声明了 1.17 就只能用 1.17 ,而应该是最低要求 1.17 的 go ,但是 1.18 也是可以用你的库的,所以你只要用 1.18 的 go 测试你的库 ok 就可以了

如果 OP 的库不是依赖 1.17 相比于低版本 go 新增的新特性,OP 甚至可以考虑把 mod 里指定更低的 go 版本

我只是喜欢 go ,自己实际项目用 go 的占比不是最多所以不敢确定对错,请 OP 实操为准
Trim21
2022-07-09 16:11:14 +08:00
@pastor #1 go 的向后兼容是不包括使用了 unsafe 包的情况的。
pastor
2022-07-09 16:21:03 +08:00
@Trim21 #2
原来如此,那可能自动化指定版本比较好了,go 发新版了就新跑一次自动化看报错没,报错了 OP 更新兼容性。github action 里指定版本,或者 action 定时任务每天跑一次 go 最新版,有问题了就提示
realpg
2022-07-09 16:40:19 +08:00
我没搞明白你的逻辑
你既然没用泛型,那么你为啥要测试泛型兼容度
如果你想测试的是,go1.18 加了泛型以后,是不是内存分配机制变化了,导致你的 unsafe 的 ptr 操作会不会造成意外的后果
你可以直接把你本地的 go mod 改成 1.18 编译,然后跑一遍单元测试
Trim21
2022-07-09 17:06:54 +08:00
@realpg #4 是的,我怕 go 的内部实现变了我的程序就挂了。

这样的话没法 commit 测试文件到仓库里。
realpg
2022-07-09 17:07:52 +08:00
@Trim21 #5
额 为啥要 commit 仓库
你本地连个单元测试都不能跑?
pastor
2022-07-09 17:17:31 +08:00
@Trim21 #5
github action 定时任务,隔一段时间用最新的 go 跑一次测试,如果测试失败了仓库的 actioin 里会有失败的。再加上 slack/discord 机器人,你就能及时收到通知然后自己去做新版本兼容了。

或者自己弄 cicd 的钩子也行。
Trim21
2022-07-09 17:20:07 +08:00
@pastor #7 我一开始也是这样想的,但是这么搞的话本地测试有点麻烦 - -
pastor
2022-07-09 17:47:58 +08:00
@Trim21 #8
本地也还好,go 自带安装管理多版本的功能,然后用对应的版本来搞,比如 `go1.10.7 test ...`,参考官方:
go.dev/doc/manage-install

图省事的话,自己写个脚本自动去查询、安装最新版本以及跑测试就好了,action 里也可以复用
janxin
2022-07-09 18:10:37 +08:00
本质问题是测试用例管理问题吧,只是在低版本中 skip 掉某些特殊用例而已。

以 Github Action 为例,比如说低版本中已存在的测试用例,只需在版本列表中加入新版本即可。

对于新的泛型测试用例,放在不用的 Go 测试项目中,只是添加一个新的 action YAML 即可。
Trim21
2022-07-09 18:24:48 +08:00
@pastor #9 原来还能这样,那就方便多了
Trim21
2022-07-09 18:25:39 +08:00
@janxin #10 是的,最终变成这么搞了,一个仓库里写了好几个 go.mod 。。。
vibbow
2022-07-09 19:50:13 +08:00
@pastor golang 不是 100%向后兼容的。
至少 SSL 这块不是。
kappa
2022-07-09 20:14:23 +08:00
用 build tag 指定呢

```
// +build go1.18
```
janxin
2022-07-09 22:37:15 +08:00
@vibbow 不保证实现兼容,只是代码编译兼容性保证 https://go.dev/doc/go1compat
pastor
2022-07-09 23:03:54 +08:00
@vibbow 如 #15 @janxin 所说,加上楼主的问题,语言兼容性好像只是 unsafe 需要注意。这个帖子让我对 go 兼容性加深了认识,哈哈哈,感谢 OP 、各位
Trim21
2022-07-10 07:31:11 +08:00
@kappa 不行,如果用 go1.18+编译器的话这个文件就会满足编译条件,然后因为用到了泛型语法就会报错。
Trim21
2022-07-18 02:05:28 +08:00
时隔一个星期后的更新。

今天看 zap 的代码才发现,自己理解错 go.mod 文件中这个 go 版本号的含义了。其实 go.mod 里面填的 go 版本并不会限制下游用户使用的 go 版本,甚至不会限制库开发者用到的 go 版本... 就算 go.mod 写了 N ,只要没用到 go N 引入的新特性,照样可以用 N-1 版本的编译器来开发和测试,甚至运行。甚至 go mod 写了 N-1 的其他用户也是可以引入你的包的。

比如 zap 的 go.mod https://github.com/uber-go/zap/blob/master/go.mod#L3 是写了 1.18 的,想要支持 1.17 版本,只要把所有的泛型代码所在的文件加上 build tag 就可以了...
Trim21
2022-07-18 02:06:49 +08:00
所以这个问题的解就是,把 go.mod 写成最新的版本,然后把对应的测试文件加上 build tag 保证旧版本的 go 编译器不会运行这些测试就可以了 - -

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/865118

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX