3

Go tips-笔记: 错误管理 48-54 mistakes

 2 years ago
source link: https://weedge.github.io/post/notions/go-tips/go-tips-07-error-management/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

48.panic

Go 新手对错误处理感到困惑是很常见的。在 Go 中,错误通常由返回的函数或方法管理类型error作为最后一个参数(这个是代码风格,error可以作为第一个参数);先了解下panic调用时的情况:

一旦panic被调用,它就会停止当前函数的执行并向上调用栈,直到当前 goroutine 出栈返回或被recover捕获;值得注意点是当前协程函数中panic了,如果有defer函数还是会执行,所以一般使用defer func(){recover()} 的形式来防止协程panic, 而且只能recover住当前协程panic, 这是因为当前协程未使用recover时已经出栈返回,函数栈帧已经无效了,调用者是没法recover的。

panic一般使用在程序启动时,一个依赖项未能初始化它时,可以使用,但是一般的做法是打印fatal日志退出;在服务启动之后,不能panic,一般记录错误日志,并且在服务运行过程中,需要对当前协程 panic recover住,以防常见的空指针访问数据,服务down掉的情况。

49.忽略何时error wrap

在处理错误时,需要向错误添加额外的上下文和/或将错误标记为特定类型。分为三种error情况进行使用:

  • 如果需要标记错误,应该创建一个自定义错误类型,比如errorCode。
  • 如果只想添加额外的上下文,应该使用fmt.Errorf %w格式指令生成wrapError类型错误,因为它不需要创建新的错误类型;wrapError会产生潜在的耦合,它使源错误通过Unwrap可供调用者使用。
  • 如果不想使用源错误追溯,不应该使用wrapError,而是错误转换,例如使用fmt.Errorf %v格式指令生成新的errorString类型错误

50.不准确地检查error类型 (重要)

这个其实就是弄懂Go1.13引入的wrapError类型错误,这个错误类型因为是层层包裹源错误,如果将以前老的代码返回的错误重构成wrapError的话,在调用的地方判断err的时候 需要用 error.Is 错误值和 error.As 错误类型 函数进行判断,Is是从error 链中递归地Unwrap err遍历是否有对应目标error值, As是从error 链中递归地Unwrap err并查看其中一个错误是否是特定error类型;这两个函数都是用了反射,如果错误链路长的话,会有一些性能折损。

51.检查error值不准确 (重要)

这里介绍的是wrapError类型错误在==比较错误值时,应该采用error.Is来判断。

52.处理error两次

这个在工程项目中,使用Go开发,打日志经常出现错误打印多条的情况,对于并发服务,如果不用logId,traceId来辅助定位,一般很难定位到一次逻辑交互的多条日志信息。这里的处理方式将多条错误通过wrap的方式 一条打印出整条逻辑链路的错误信息出来。工程实践小细节吧,如果考虑性能影响,需要折中考虑了。

53.不处理错误 (工程规范)

忽略错误都应该使用_标识符显式标示,在不处理错误的函数调用地方,加上对应注释上下文逻辑说明为什么可以忽略。。。

54.不处理延迟错误

如果函数返回的错误需要考虑defer函数中的函数调用是否返回错误,则在defer闭包函数中先判断函数中的err是否不为nil, 是则直接闭包函数返回,否则将defer 闭包函数中处理的逻辑函数错误赋值给err。如果想忽略它,使用_标识符标示。

  • panic是 Go 中处理错误的一个选项。它应该只在不可恢复的情况下谨慎使用:例如,发出程序员错误信号或加载强制依赖项失败时。
  • 包装错误允许标记错误和/或提供额外的上下文。但是,错误包装会产生潜在的耦合,因为它使源错误可供调用者使用。如果想防止这种情况发生,请不要使用错误包装。
  • 如果使用 Go 1.13 fmt.Errorf %w指令返回wrapError类型错误,则必须分别使用errors.As 或者errors.Is将错误与类型或值进行比较。
  • 要传达预期的错误,请使用错误哨兵(错误值)。意外错误应该是特定的错误类型。
  • 在大多数情况下,一个错误应该只处理一次。记录错误就是处理错误。因此,必须在记录或返回错误之间做出选择。在许多情况下,错误包装是解决方案,因为它允许为错误提供额外的上下文并返回源错误。
  • 忽略错误,无论是在函数调用期间还是在函数中defer,都应该使用_标识符显式标示。否则,未来的读者可能会混淆这是故意的还是失误。
  • 在许多情况下,不应该忽略函数返回的错误defer。根据上下文,直接处理它或将其传播给调用者。如果想忽略它,使用_标识符标示。

</div


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK