Go代码审查:检查什么才能让代码不炸裂

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

Go代码审查:检查什么才能让代码不炸裂

\n\n

代码审查不仅仅是Jira里的一个勾选标记,也不是在拉取请求评论中与同事争吵的理由。这可能是避免在生产环境中自食其果的最诚实的方式。而当谈到Go——这种因简洁而备受喜爱、又因“泛型在哪里?”(剧透:它们已经有了)而遭人憎恨的语言时——审查就成了一门艺术。在本文中,我们将详细分析在Go代码审查中具体要关注什么,让你的代码不仅能运行,还能赏心悦目。开始吧!

\n\n

1. 错误处理:不要忽略,不要害怕

\n\n

Go没有异常。这里一切都很诚实:如果函数可能失败,它会返回error。新手最常见的问题是通过下划线忽略错误。请记住:“永远不要忽略错误”——这不仅仅是一句口头禅,而是一条法则。

\n\n

代码中要检查什么:

\n
    \n
  • 检查 err != nil —— 只要函数返回错误,就必须进行检查。即使你确信“这里不会出错”。
  • \n
  • 记录日志或向上传递 —— 错误要么附带上下文记录日志,要么向上返回。忽略错误是不好的做法。
  • \n
  • 与哨兵错误比较 —— 使用errors.Is()和errors.As(),而不是直接使用==比较。
  • \n
\n\n
// 不好:忽略错误\nfile, _ := os.Open("config.yaml")\n\n// 好:检查并记录日志\nfile, err := os.Open("config.yaml")\nif err != nil {\n    log.Printf("无法打开配置文件: %v", err)\n    return err\n}\ndefer file.Close()\n
\n\n

2. 协程与并发:混乱中的秩序

\n\n

协程是Go的超能力。但能力越大,责任越大。在审查中,我们经常看到协程泄漏、数据竞争和死锁。没有并发检查的Go代码审查,就像开着跑车却不系安全带。

\n\n

协程检查清单:

\n
    \n
  • 启动协程 —— 始终控制其生命周期。使用sync.WaitGroup或上下文。
  • \n
  • 数据竞争 —— 检查对共享数据的访问是否受到互斥锁或通道的保护。运行go test -race。
  • \n
  • 协程中的恐慌 —— 如果协程发生恐慌,整个程序都会崩溃。在生产代码中务必使用recover。
  • \n
\n\n
// 不好:不受控制的协程\ngo func() {\n    // 可能崩溃并杀死整个进程\n    doWork()\n}()\n\n// 好:使用WaitGroup和recover\nvar wg sync.WaitGroup\nwg.Add(1)\ngo func() {\n    defer wg.Done()\n    defer func() {\n        if r := recover(); r != nil {\n            log.Printf("协程崩溃: %v", r)\n        }\n    }()\n    doWork()\n}()\nwg.Wait()\n
\n\n

3. 接口:小而精

\n\n

在Go中,接口是契约。但与Java不同,它们不必是庞大的。Go社区有一个原则:“接口越小越好”。一个方法——完美。两个——正常。三个——已经可疑了。

\n\n

要检查什么:

\n
    \n
  • 接口大小 —— 如果超过3-4个方法,考虑拆分。
  • \n
  • 接受接口,返回结构体 —— Go的经典智慧。它使代码灵活且可测试。
  • \n
  • 不要预先定义接口 —— 让消费者而不是生产者来创建它们。
  • \n
\n\n
// 不好:庞大的接口\ntype Storage interface {\n    Save(data []byte) error\n    Load(id string) ([]byte, error)\n    Delete(id string) error\n    List() ([]string, error)\n    Connect() error\n    Close() error\n}\n\n// 好:小接口\ntype Saver interface {\n    Save(data []byte) error\n}\ntype Loader interface {\n    Load(id string) ([]byte, error)\n}\n

博客

书籍推荐