如何捕获特定的错误

huangapple go评论68阅读模式
英文:

How to `catch` specific errors

问题

例如,我正在使用一个Go标准库函数,如下所示:

func Dial(network, address string) (*Client, error)

这个函数可能会返回错误,我只关心报告"连接丢失"或"连接被拒绝"的错误,然后编写一些代码来修复这些错误。
看起来像这样:

client, err := rpc.Dial("tcp", ":1234")
if err == KindOf(ConnectionRefused) {
  // 做一些处理
}

另外,如何获取特定标准库函数可能返回的所有错误?

英文:

For example, I am using one Go standard library function as:

func Dial(network, address string) (*Client, error)

This function may return errors, and I just care about errors which report "connection lost" or "connection refused", then do some code to fix these.
It seems like:

client, err := rpc.Dial("tcp", ":1234")  
if err == KindOf(ConnectionRefused) {
  // do something
}

What's more, how to get all the errors a specific standard library function may return?

答案1

得分: 15

在现代的Go语言中,最好的一般方法是使用标准库中的errors.Iserrors.As函数来实现。

对于原始问题中的示例,可以很简单地实现如下:

if errors.Is(err, syscall.ECONNREFUSED) {
    // 连接被拒绝的错误
} else {
    // 其他类型的错误
}

然而,这种方法只适用于那些正确包装/创建以使用这些功能的错误。有时候你可能需要混合使用errors.Iserrors.As和字符串比较的方法。我制作了一个视频,详细介绍了其中的一些细节,供有兴趣的人参考。


我的旧回答:

没有标准的方法来实现这个。

最直接的方法是,只有在没有其他方法可用时才使用,将错误字符串与预期值进行比较:

if err.Error() == "connection lost" { ... }

或者在某些情况下更加健壮的方法是:

if strings.HasSuffix(err.Error(), ": connection lost") { ... }

但是许多库会返回特定的错误类型,这样做会更加容易。

在你的情况下,与net包相关的各种导出错误类型是相关的:AddrErrorDNSConfigErrorDNSErrorError等等。

你可能最关心的是net.Error,它用于网络错误。所以你可以这样检查:

if _, ok := err.(net.Error); ok {
    // 你知道它是一个net.Error实例
    if err.Error() == "connection lost" { ... }
}

另外,如何获取特定标准库函数可能返回的所有错误?

唯一可靠的方法是阅读库的源代码。在采取这种极端措施之前,首先可以简单地阅读godoc文档,就像net包的情况一样,其中的错误已经有很好的文档说明。

英文:

In modern Go, the best general way to do this is with the errors.Is and errors.As functions in the standard library.

For the example in the original question, this is quite straight forward:

if errors.Is(err, syscall.ECONNREFUSED) {
    // Connection refused error
} else {
    // Some other kind of error
}

However, this only works for errors which are properly wrapped/created to use these capabilities. Sometimes you may need to mix-and-match the use of errors.Is and errors.As with string comparison. I've made a video that goes into some of these details for those interested.

<hr>

My old answer:

There's no standard way to do this.

The most obvious way, which should only be used if no other method is available, is to compare the error string against what you expect:

if err.Error() == &quot;connection lost&quot; { ... }

Or perhaps more robust in some situations:

if strings.HasSuffix(err.Error(), &quot;: connection lost&quot;) { ... }

But many libraries will return specific error types, which makes this much easier.

In your case, what's relevant are the various error types exported by the net package: AddrError, DNSConfigError, DNSError, Error, etc.

You probably care most about net.Error, which is used for network errors. So you could check thusly:

if _, ok := err.(net.Error); ok {
    // You know it&#39;s a net.Error instance
    if err.Error() == &quot;connection lost&quot; { ... }
}

> What's more, how to get all the errors a specific standard library function may return?

The only fool-proof way to do this is to read the source for the library. Before going to that extreme, a first step is simply to read the godoc, as in the case of the net package, the errors are pretty well documented.

答案2

得分: 4

你现在可以使用errors.Is()函数来比较一些标准错误:

client, err := net.Dial("tcp", ":1234")
if errors.Is(err, net.ErrClosed) {
    fmt.Println("连接已关闭。")
}

一个常见的文件打开场景:

file, err := os.Open("non-existing")
if err != nil {
    if errors.Is(err, fs.ErrNotExist) {
        fmt.Println("文件不存在")
    } else {
        fmt.Println(err)
    }
}

更新
如果你想检查错误类型,你也可以使用errors.As()

client, err := net.Dial("tcp", ":1234")
var errC = net.ErrClosed
if errors.As(err, &errC) {
    fmt.Printf("连接已关闭:%s", errC)
}
client.Close()

更详细的解释可以在Go Blog中找到。

英文:

You can now use the errors.Is() function to compare some standard errors:

client, err := net.Dial(&quot;tcp&quot;, &quot;:1234&quot;)
if errors.Is(err, net.ErrClosed) {
	fmt.Println(&quot;connection has been closed.&quot;)
}

A common file opening scenario:

file, err := os.Open(&quot;non-existing&quot;);
if err != nil {
	if errors.Is(err, fs.ErrNotExist) {
		fmt.Println(&quot;file does not exist&quot;)
	} else {
		fmt.Println(err)
	}
}

UPDATE
You can also use errors.As() if you'd like to check the error type:

client, err := net.Dial(&quot;tcp&quot;, &quot;:1234&quot;)
var errC = net.ErrClosed
if errors.As(err, &amp;errC) {
	fmt.Printf(&quot;connection has been closed: %s&quot;, errC)
}
client.Close()

A more detailed explanation can be found in the Go Blog.

huangapple
  • 本文由 发表于 2017年4月25日 16:47:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/43605790.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定