Go 1.28 新增两个 vet 检查项:scannererr 与 sqlrowserr 专抓循环末尾漏掉的 Err()
Go 1.28 还在开发中,按计划 2027-02 发布。以下内容来自官方 next release notes 草稿(tip.golang.org/doc/next),属于工作稿,正式发布前可能变化。
go vet:两个新分析器
scannererr:bufio.Scanner 循环后没查错
bufio.Scanner.Scan 返回 false 有两种可能:真的读完了,或者中途遇到了扫描错误 / I/O 错误。如果循环结束后不调用 sc.Err(),后一种情况会被静默吞掉——循环看起来正常退出,实际数据被截断。
正确的写法是循环之后补一段错误检查:
for sc.Scan() {
// ...
}
if err := sc.Err(); err != nil { // scannererr 会提醒你补上这段
// ...
}
scannererr 就是用来提示这段缺失的检查。
sqlrowserr:sql.Rows.Next 循环同理
sql.Rows.Next 的迭代循环有一模一样的问题:Next() 返回 false 时,可能是结果集正常结束,也可能是迭代过程中出错了。两者不区分,就会把「结果比预期少」和「查询出错」混为一谈。
这个分析器要求循环结束后检查 rows.Err(),把迭代错误单独识别出来。
这两个分析器针对的是同一类隐性 bug:循环体每次判断都正常走完,底层其实已经报错,只是没人接收。
引导(bootstrap)版本要求
Go 1.28 现在要求用 Go 1.26.0 或更高版本引导构建,这一要求延续了 Go 1.26 release notes 中的说明。按规划,Go 1.30 会要求 Go 1.28.0 的某个小版本或更高。
标准库变化(节选)
encoding:Encoding.EncodedLen 在编码长度溢出 int 时改为 panic,不再返回负数。此前返回负值容易在后续使用中引发越界或其它错误。
go/ast:新增 ResolveFile,对一棵 ast.File 语法树执行旧的语法标识符解析。该解析方式已经弃用,新应用应改用 go/types。提供这个函数,是为了方便那些主要用 SkipObjectResolution 模式解析文件、偶尔又需要旧解析的应用做迁移。
net:IPMask、IPNet、HardwareAddr 三个类型现在都实现了 encoding.TextUnmarshaler。该方法既能识别这些类型当前的序列化格式,也能识别计划中的未来格式——未来格式是 JSON 可读的,而当前格式是 base64。未来格式会在之后的 Go 版本中成为默认。采用两步走,是为了让本次生成的 JSON 仍能被更早的 Go 版本读取。
net/http:当 http_proxy / https_proxy / no_proxy 的大写与小写版本同时存在且取值不同时,ProxyFromEnvironment 现在优先使用小写版本。该改动通过扩展同时影响 DefaultTransport 与 DefaultClient 的默认代理查找。环境里大小写代理变量不一致时,行为会发生变化——很多环境同时存在 HTTP_PROXY 与 http_proxy,之前取大写,现在取小写。
net/url:新增 MustParse,解析成功返回 *URL,失败则 panic。适合用有效的 URL 字符串常量来初始化变量。
os/exec:Linux 上 SysProcAttr 现在支持对新启动的子进程强制 Landlock 策略与 PR_SET_NO_NEW_PRIVS 标志。
testing:新增 Subtest 便捷函数,组合 testing.(*T).Run 与 testing/synctest.Test。
其他
Go 1.28 的 Collections 工作组有一个伞形提案,计划为 1.28 标准库引入泛型集合:canonical set.Set、带自定义 hasher 的 map/set、有序 map、泛型二叉堆。这是提案阶段,不是已落地的特性。
官方 next release notes:https://tip.golang.org/doc/next