GO错误处理【5】显式错误处理

按照上一章的说法,我所有的函数方法都要后面加一个err?

要不然没法一层一层往上传递?

你抓到 Go 语言的"命脉"了!是的,在 Go 赛道,几乎所有涉及 IO、数据库、网络或复杂业务的函数,标配都是返回 (数据, error)。

这确实和 PHP 习惯"直接返回数据,出事抛异常"不一样。在 Go 里,这叫"显式错误处理"。

1. 为什么要一层层往上交?

想象你在 PHP 里:

复制代码
// PHP 逻辑
function getInfo() {
    return $db->query(); // 如果这里崩了,直接炸到顶层,中间的逻辑管不住
}

而在 Go 里,这就是一场接力赛:

  • Repo 层:拿到最原始的错,包一下,交给 Logic。
  • Logic 层:看看这个错能不能救(比如读缓存),救不了,再包一下上下文,交给 Handler。
  • Handler 层:最后拍板,是给用户看"系统维护",还是记录一条"严重报警"。

如果没有每一层后面的 error,这个接力棒就断了,顶层根本不知道底层发生了什么,也就没法写出有意义的日志。

2. 难道所有函数都要加 err 吗?

不一定。你可以根据"有没有可能失败"来判断:

  • 需要加 err 的(涉及外部环境):
    • 查数据库、读写文件、调远程接口、解析 JSON、字符串转数字。
    • 准则:只要这个函数依赖"运气"(环境、网络、用户输入),就得带 err。
  • 不需要加 err 的(纯逻辑运算):
    • 计算两个数之和、拼接两个字符串、从结构体里取一个已经存在的字段。
    • 准则:只要这个函数是"确定性"的,给同样的输入一定有同样的输出,就不需要 err。

3. 写起来会不会很累?

刚开始你会觉得 if err != nil 写得手酸,但你会发现这种写法带来的安全感:

  1. 没有隐藏炸弹:你盯着代码看,哪里有 err 哪里就有风险,一目了然,不需要猜哪里会抛异常。
  2. 强制思考:Go 强制你面对错误。PHP 里你可能会忘了 try-catch,但 Go 里如果你忽略了返回的 err,编译器或静态检查工具会跳出来提醒你。

4. 报错链条实战总结

你可以把这套公式背下来:

  1. 底层 (Repo): return nil, fmt.Errorf("repo context: %w", err)
  2. 中层 (Logic): return nil, fmt.Errorf("logic context: %w", err)
  3. 顶层 (Handler): infra.Log("api").Error("final message", "err", err)

这就是你之前担心的"日志白写了"的终极答案: 底层和中层只负责"攒信息",顶层负责"按开关写日志"。

相关推荐
FungLeo14 小时前
成为全栈·Go 后端篇·三轮代码审阅之后:把可读性和证据做成工程规则
golang·go·ast·静态检查·成为全栈·代码审阅
我不会起名字32217 小时前
Redis 从 0 到 1(二十八):Redis 抖一下,重试把它打挂了——超时/重试/熔断的 Go 封装
redis·go·超时·熔断·重试
xyzzklk18 小时前
变相解决华为Mate 8锁屏后无法建立入站网络连接
linux·运维·服务器·网络·华为·go·安卓
vipxieliang2 天前
语言对比卡:PHP vs Go vs Java 的优缺点、适用场景与「为什么选 PHP」
java·go·php
我不会起名字3223 天前
Redis 从 0 到 1(二十七):JSON 体积是 Protobuf 的 3.7 倍?3 种序列化的 Go 基准测试
redis·go·序列化·protobuf·messagepack
我不会起名字3223 天前
Redis 从 0 到 1(二十三):一个热 key 打到 10 万 QPS——hotkey 与本地缓存的 Go 实现
redis·缓存·go·qps·hotkey
Patrick_Wilson3 天前
Go 为什么需要 defer?从函数怎么收尾说起
后端·go·编程语言
Patrick_Wilson3 天前
从文本输出理解 Go 方法与接口
后端·go·编程语言
Patrick_Wilson3 天前
读懂一个 Go JSON 处理函数:从输入数据追踪结构体、校验与错误返回
go·json·编程语言
Patrick_Wilson3 天前
第一次读 Go 项目:从两个源码文件弄清 package、import 和 go.mod
后端·go·编程语言