基于Go中错误类型的细粒度错误处理

基于Go中错误类型的细粒度错误处理,go,error-handling,try-catch,Go,Error Handling,Try Catch,TLDR:某些库中有一个函数,它通过网络执行某些操作,可能会出错。错误可能表示输入参数错误、凭据无效、网络故障。。。和我不知道还有什么。这就是问题所在 我如何知道,预期会出现什么错误,以正确处理(比如)网络故障 长版本: 这是处理Go代码中类似错误的一种非常常见的方法 function f0() (v Value, err Error) { v2, err := f3() if err != nil { return } v1, err := f2(v2) if e

TLDR:某些库中有一个函数,它通过网络执行某些操作,可能会出错。错误可能表示输入参数错误、凭据无效、网络故障。。。和我不知道还有什么。这就是问题所在

我如何知道,预期会出现什么错误,以正确处理(比如)网络故障

长版本: 这是处理Go代码中类似错误的一种非常常见的方法

function f0() (v Value, err Error) {
  v2, err := f3()
  if err != nil {
    return
  }

  v1, err := f2(v2)
  if err != nil {
    return
  }

  v, err = f1(v1)
  return
}
在Go代码中,不记录返回的错误类型也是很常见的。 我们不要忘记围棋中另一个常见的成语

err = errors.New("Boo! I failed") // returns trivial errorString
这导致出现这样的情况,
f0()
的调用者可能会得到几十个错误(在我的示例中,如果
f3()
f1()
也执行一些调用),这些错误代表了概念上不同的问题


如何区分所有这些错误?

实现这个最小接口的任何东西都是错误

type error interface {
    Error() string
}
简单的解决办法是

type BadCredsError string

func (e BadCredsError) Error() string {
      return string(e)
} 
基本上,只需定义自己的类型,然后就可以使用类型开关或类型断言来确定特定的错误类型,就像在C#和Java等更多面向对象语言中看到的那样


顺便说一下,我的示例就像一个2秒的伪代码片段。围棋博客在这里进行了更深入的讨论

谢谢。如果我设计自己的库,那就好了。但是如果我已经使用了一些库呢?我是否应该承认,这个图书馆设计得很糟糕,我自己修复它?问题是,这样的代码在围棋世界里很常见。@edio是的,你必须习惯它。如果C#中的库只是抛出了
新异常(“此处出现错误字符串”)
,那么情况也是一样,作者只是选择使用
InvaidOperationException
之类的东西。通常人们使用
string.contains
来识别Go中的错误。这是惯例,不是强制的,大多数库都遵循它。有关更多错误技巧,请参阅。在我看来,如果库/包对它产生的错误(至少是它的合理代码可能要检查/处理的错误)没有采取合理的措施,那么它的API充其量是不完整的,您应该针对库提交一个问题。请注意,在
BadCredsError.Error()中
方法无法将
e
转换为
string
,因为
e
是指针。您必须执行以下操作:
string(*e)
@icza true。我更改了接收类型。Edio—最终,错误数据包含在哪里并不重要。重要的是它的一致性。将该信息与类型本身进行通信并不能保证一致性。如果您的库出现严重错误,您将陷入困境。如果没有,那么您应该忘记需要不同类型来识别不同错误的概念,并进行一些基本的字符串匹配。老实说,强类型错误只是为了弥补差劲/不一致的开发人员的不足。它们没有增加真正的价值。