Go语言中的静态代码分析之错误检查 Golang errcheck工具使用

2次阅读

errcheck 是一个独立静态检查器,专用于发现 go 中返回 Error 却未被显式处理或忽略的情况,如 os.remove() 后无 err 判断、json.unmarshal() 错误丢失、defer f.close() 返回值被无视等。

Go语言中的静态代码分析之错误检查 Golang errcheck工具使用

errcheck 是什么,它能发现哪些错误

errcheck 不是 Go 官方工具,而是一个独立的静态检查器,专门用来揪出 error 值被忽略的情况。它不检查 error 是否处理得“对”,只看是否被显式丢弃——比如调用一个返回 error 的函数后,既没赋值给变量,也没用 _ 显式忽略,更没做任何判断或日志,那就是它的目标。

常见错误现象包括:os.Remove("file.txt") 后没接 if err != niljson.Unmarshal(data, &v) 返回的 error 直接消失;甚至 defer f.Close()f.Close() 的返回值被完全无视。

它不会报错:显式用了 _ = f.Close()_, _ = strconv.Atoi(s);也不会报错:函数签名里根本没返回 error。它只盯住“有 error 返回但没被消费”这个动作。

怎么装、怎么跑、默认行为有哪些坑

安装很简单:go install github.com/kisielk/errcheck@latest(注意不是 go get,新版 Go 推荐用 go install)。装完后命令就是 errcheck,默认检查当前目录下所有 .go 文件。

立即学习go语言免费学习笔记(深入)”;

容易踩的坑:

  • 它默认跳过测试文件(*_test.go),如果想检查测试里的 error 忽略,得加 -tests 参数
  • 它默认只检查导出函数调用(即首字母大写的函数),像 fmt.println() 这种不报,但 os.Open() 会报——因为后者返回 error 且是导出的;内部包函数若没导出,errcheck 看不见
  • 它不识别自定义 error 包装逻辑,比如你写了 MustOpen() 且文档说“panic on error”,errcheck 仍会报它,除非你用 //nolint:errcheck 注释压制

怎么跳过特定行或函数

errcheck 支持两种压制方式,选哪种取决于你是否真想忽略,还是只是暂时绕过。

临时跳过某一行:

os.Remove("tmp.txt") //nolint:errcheck

全局禁用某个函数(比如你确定 log.printf 不会返回有意义的 error):

  • 在项目根目录建 .errcheck.conf,写入:ignore: log.Printf
  • 或者运行时加参数:errcheck -ignore 'log.Printf'(注意正则转义)
  • 常见需忽略的函数: log.Print*fmt.Print*io.WriteString(当写入 os.Stdout 时)

注意:-ignore 是按函数全名匹配的,不是按包名。写成 fmt.Printf 才生效,不能只写 Printf

go vet、staticcheck 有什么区别

它们定位不同,不是替代关系:

  • go vet 自带,检查的是明显可疑的代码模式(比如 printf 格式串和参数不匹配),但它几乎不管 error 忽略
  • staticcheck 更重,能发现 error 被忽略,但它是通用规则(SA1019 类),不如 errcheck 专注和灵敏;而且 staticcheck 默认不开这个检查,得手动启用 -checks=all 或指定 SA1019
  • errcheck 更轻、更快、专一,适合 CI 里单独跑,也适合开发时快速扫一遍 error 漏洞点

实际建议:CI 流水线里同时跑 go veterrcheck,前者保基础,后者守 error;本地开发可以只跑 errcheck,省时间。

真正难的是判断哪些 error 其实不该忽略——比如 os.RemoveAll 失败后要不要重试?errcheck 不回答这个问题,它只负责把问题暴露出来。剩下的,得人来权衡。

text=ZqhQzanResources