0

0

Golang初级项目中错误处理如何设计

P粉602998670

P粉602998670

发布时间:2026-01-06 13:52:02

|

617人浏览过

|

来源于php中文网

原创

Go初级项目中绝大多数场景应直接使用内置error接口,仅在需额外字段或特定行为时才自定义错误类型;if err != nil后95%应return err,仅启动失败等不可恢复场景用log.Fatal;错误首次发生处记录日志并%w包装,最外层统一补全上下文;测试需mock依赖错误并用errors.Is/As验证错误处理逻辑。

golang初级项目中错误处理如何设计

错误类型该用 error 还是自定义结构体?

Go 初级项目里,绝大多数场景直接用内置的 error 接口就够了。别一上来就写 type MyError struct{...} —— 除非你需要额外字段(比如错误码、请求 ID、重试次数)或要实现特定行为(如 Unwrap()Is() 判断)。标准库fmt.Errorferrors.New 足够表达上下文,配合 %w 包装还能保留调用链。

常见错误现象:过早抽象出带字段的错误结构,结果全项目只有 1 处用到;或者每个函数都返回不同结构体,导致上层 switch err.(type) 越写越臃肿。

  • 只在需要区分错误语义且影响控制流时才自定义错误类型(例如:网络超时 vs 参数校验失败)
  • errors.Is(err, targetErr) 替代类型断言判断是否为某类错误
  • errors.As(err, &e) 提取底层错误值,而不是层层断言
  • 避免在错误结构体中嵌入业务数据(如用户 ID),容易泄露敏感信息或破坏封装

if err != nil 后该 return 还是 log.Fatal

95% 的情况应该 return err,把错误交给调用方决定如何处理。只有两种例外:程序启动失败(如配置加载失败、端口被占)、main 函数末尾无法继续运行时,才用 log.Fatalos.Exit(1)

使用场景差异明显:HTTP handler 里遇到数据库错误,应返回 500 并记录日志,而不是让整个服务崩掉;CLI 工具解析参数失败,可以 fmt.Fprintln(os.Stderr, err); os.Exit(1),但前提是它真不能继续执行了。

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

TTSMaker
TTSMaker

TTSMaker是一个免费的文本转语音工具,提供语音生成服务,支持多种语言。

下载
  • 绝不在库函数或中间件里调用 log.Fatal —— 这等于替使用者做了终止决策
  • 所有可恢复的错误(I/O、网络、校验失败)都向上返回,由最外层(如 HTTP handler、main)统一处理
  • 如果用了 log.Fatal,确保它只出现在 main() 或明确的初始化入口,且有清晰注释说明“此处不可恢复”

日志记录和错误传播怎么不重复也不丢失?

核心原则:只在错误首次发生处加日志(含上下文),传播时用 %w 包装,不再重复打日志;最终处理处(如 handler)再统一记录一次,带上 trace ID 或请求路径等现场信息。

容易踩的坑:每个 if err != nil 都跟一句 log.Printf("failed to xxx: %v", err),结果一个请求失败打出 5 条日志,还全是重复堆;或者完全不记录,只返回错误,线上出问题时毫无线索。

  • 在错误生成点记录(如 DB 查询失败),用 log.With(...).Errorf("db query failed: %w", err)
  • 传播时不记录,只用 fmt.Errorf("calling service Y: %w", err)
  • 最外层捕获后,用结构化日志补全请求上下文:
    log.With(zap.String("path", r.URL.Path)).Error("request failed", zap.Error(err))
  • 避免用 err.Error() 拼接日志字符串 —— 会丢掉包装链和原始类型信息

测试中怎么验证错误路径是否覆盖到位?

初级项目最容易漏测的是错误分支:只测正常流程,不构造依赖失败来触发 if err != nil 分支。验证重点不是“有没有 return err”,而是“返回的错误是否包含足够信息、能否被正确识别”。

性能影响不大,但逻辑覆盖不到位会导致上线后错误静默或误判。比如 mock 数据库返回 sql.ErrNoRows,但业务代码没用 errors.Is(err, sql.ErrNoRows) 判断,而是直接返回原错误,上层就无法区分“查无结果”和“连接异常”。

  • 对每个外部依赖(DB、HTTP client、文件读写)都 mock 其错误返回,至少覆盖 1–2 种典型错误
  • errors.Iserrors.As 断言错误类型,而不是比较 err.Error() 字符串
  • 测试 error 包装链:用 errors.Unwrap 或第三方库(如 github.com/pkg/errorsCause)检查底层错误是否可达
  • 避免测试里出现 if err != nil { t.Fatal(err) } —— 这会让测试通过但掩盖错误处理缺陷
真正难的不是写 if err != nil,是想清楚谁该负责处理、要不要暴露细节、日志打在哪一层、测试时能不能逼出那个分支。这些决策一旦定错,后期改起来比加功能还费劲。

相关专题

更多
golang如何定义变量
golang如何定义变量

golang定义变量的方法:1、声明变量并赋予初始值“var age int =值”;2、声明变量但不赋初始值“var age int”;3、使用短变量声明“age :=值”等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

177

2024.02.23

golang有哪些数据转换方法
golang有哪些数据转换方法

golang数据转换方法:1、类型转换操作符;2、类型断言;3、字符串和数字之间的转换;4、JSON序列化和反序列化;5、使用标准库进行数据转换;6、使用第三方库进行数据转换;7、自定义数据转换函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

226

2024.02.23

golang常用库有哪些
golang常用库有哪些

golang常用库有:1、标准库;2、字符串处理库;3、网络库;4、加密库;5、压缩库;6、xml和json解析库;7、日期和时间库;8、数据库操作库;9、文件操作库;10、图像处理库。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

336

2024.02.23

golang和python的区别是什么
golang和python的区别是什么

golang和python的区别是:1、golang是一种编译型语言,而python是一种解释型语言;2、golang天生支持并发编程,而python对并发与并行的支持相对较弱等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

208

2024.03.05

golang是免费的吗
golang是免费的吗

golang是免费的。golang是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的开源编程语言,采用bsd开源协议。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

388

2024.05.21

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

194

2025.06.09

golang相关判断方法
golang相关判断方法

本专题整合了golang相关判断方法,想了解更详细的相关内容,请阅读下面的文章。

189

2025.06.10

golang数组使用方法
golang数组使用方法

本专题整合了golang数组用法,想了解更多的相关内容,请阅读专题下面的文章。

191

2025.06.17

PPT动态图表制作教程大全
PPT动态图表制作教程大全

本专题整合了PPT动态图表制作相关教程,阅读专题下面的文章了解更多详细内容。

13

2026.01.07

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Git 教程
Git 教程

共21课时 | 2.5万人学习

Git版本控制工具
Git版本控制工具

共8课时 | 1.5万人学习

Git中文开发手册
Git中文开发手册

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号