解释 Golang 错误代码

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

Interpreting Golang Error codes

问题

我看到大多数 Go 语言错误处理的示例都是将任何错误传递回堆栈。但是在某个时候,这些错误需要进行解释,这就是我正在尝试做的事情。

以下是我尝试的一部分代码:

resp, err := http.Get(string(url))
defer out_count.Dec()

if err != nil {
    switch err {
    case http.ErrBodyReadAfterClose:
        fmt.Println("Read after close error")
    case http.ErrMissingFile:
        fmt.Println("Missing File")
    {一些其他的 case}
    case io.EOF:
        fmt.Println("EOF error found")
    default:
        fmt.Printf("Error type is %T\n", err)
        panic(err)
    }
    return
}

然而,在我的当前情况下,这并不起作用(已编辑以删除 URL):

ERROR: Failed to crawl "http://{已删除的 URL}"
Error type is *url.Error
panic: Get http://{已删除的 URL}: EOF

goroutine 658 [running]:
runtime.panic(0x201868, 0x106352c0)
        /usr/lib/go/src/pkg/runtime/panic.c:279 +0x1a0
github.com/cbehopkins/grab/grab.crawl(0x10606210, 0x27, 0x105184b0, 0x105184e0, 0x10500460)

我无法找到一种方法来使 switch 语句捕捉到这个错误,因为错误的文本每次都会改变,并且没有明确的值可以匹配(因为 URL 每次都会改变)。也许我可以在 case 语句中使用某种正则表达式匹配或者对错误字符串进行子切片,但这感觉像是一种非常糟糕的解决方法。

有什么建议吗?肯定有一种惯用的方式来捕捉这种错误,对吗?

英文:

So most examples of go error handling I see just pass any errors back up the stack. At some point these need interpreting and this is what I am trying to do.
Here's a snippet of my attempt:

    resp, err := http.Get(string(url))
    defer out_count.Dec()

    if err != nil {

           switch err {
            case http.ErrBodyReadAfterClose:
                    fmt.Println("Read after close error")
            case http.ErrMissingFile:
                    fmt.Println("Missing File")
            {some more cases here}
            case io.EOF:
                    fmt.Println("EOF error found")
            default:
                    fmt.Printf("Error type is %T\n", err)
                    panic(err)
            }
            return

This isn't working though for my current case(edited to remove url}:

ERROR: Failed to crawl "http://{removed URL}"
Error type is *url.Error
panic: Get http://{removed url}: EOF

goroutine 658 [running]:
runtime.panic(0x201868, 0x106352c0)
        /usr/lib/go/src/pkg/runtime/panic.c:279 +0x1a0
github.com/cbehopkins/grab/grab.crawl(0x10606210, 0x27, 0x105184b0, 0x105184e0, 0x10500460)

I can't figure out a way to get the switch statement to catch this error since the text of the error changes every time and has no explicit value I can catch against. (as the URL changes all the time). Now maybe I could do some sort of regex match in the case statement or sub-slice the error string, but that feels like a very bad way to solve this problem.

Any suggestions? There must be an idiomatic way to catch errors such as this surely?

答案1

得分: 8

在你的代码中,最简单的方法是在包级别定义错误值:

var URLFetchError = errors.New("无法获取URL")

url := "http://www.google.com"
res, err := http.Get(url)
if err != nil {
    return URLFetchError
}

然后,switch 语句可以这样写:

switch err {
case http.ErrBodyReadAfterClose:
    fmt.Println("读取关闭后的错误")
case URLFetchError:
    fmt.Println("获取URL时发生错误")
}

如果你想在错误中传递更多信息,可以创建自定义错误:

type MyError struct {
    URL string
}

func (e MyError) Error() string {
    return fmt.Sprintf("获取时发生错误:%v", e.URL)
}

然后,可以在需要时创建此错误。例如:

url := "http://www.google.com"
res, err := http.Get(url)
if err != nil {
    return MyError{url}
}

最后,在错误检查方法中,你可以使用类型断言来获取错误:

switch err.(type) {
case MyError:
    fmt.Println("错误:", err)
default:
    fmt.Println("没有错误")
}

在你的情况下,由于你有多种类型的错误,你可以在嵌套的 switch 中进行检查:

switch err {
case http.ErrBodyReadAfterClose:
    fmt.Println("读取关闭后的错误")
case http.ErrMissingFile:
    fmt.Println("文件丢失")
case io.EOF:
    fmt.Println("发现EOF错误")
default: // 检查自定义错误
    switch err.(type) {
    case MyError:
        fmt.Println("自定义错误:", err)
    default:
        panic(err)
    }
}
英文:

The simplest way would be to have package level error values in your code:

var URLFetchError = errors.New("Cannot fetch URL")

url := "http://www.google.com"
res, err := http.Get(url)
if err != nil {
	return URLFetchError
}

The switch then becomes:

switch err {
case http.ErrBodyReadAfterClose:
	fmt.Println("Read after close error")
case URLFetchError:
    fmt.Println("Error fetching URL")

If you want to pass more information with the error, you can create your own custom errors:

type MyError struct {
	URL string
}

func (e MyError) Error() string {
	return fmt.Sprintf("Error getting: %v", e.URL)
}

Then, you can create this error whenever required. For example:

url := "http://www.google.com"
res, err := http.Get(url)
if err != nil {
	return MyError{url}
}

Finally, in your error checking method, you can use type switches instead of simple switches to get the error:

switch err.(type) {
case MyError:
	fmt.Println("Error:", err)
default:
	fmt.Println("No Error")
}

In your case, since you have a mix of regular error, you can include this check in a nested switch:

switch err {
case http.ErrBodyReadAfterClose:
	fmt.Println("Read after close error")
case http.ErrMissingFile:
	fmt.Println("Missing File")
case io.EOF:
	fmt.Println("EOF error found")
default: // check for custom errors
	switch err.(type) {
	case MyError:
		fmt.Println("custom error:", err)
	default:
		panic(err)
	}
}

答案2

得分: 1

你可以实现错误接口并创建自己的错误,这样可能更容易处理。

对于运行时错误,也就是 panic。你可以在你认为可能会发生 panic 的函数中包含 recover() 来进行恢复。它会在一个发生 panic 的函数返回之前被调用。

defer func() {
    if r := recover(); r != nil {
        if _, ok := r.(runtime.Error); ok {
            err = r.(error) //panic(r)
        }
        err = r.(error)
    }
}()
英文:

You can implement the error interface and create your own errors which you may find easier to deal with.

For runtime errors a.k.a panic. You can recover by including recover() in a function that you think may panic. It get's called before a panicing function returns.

defer func() {
    if r := recover(); r != nil {
		if _, ok := r.(runtime.Error); ok {
				err = r.(error) //panic(r)
			}
			err = r.(error)
		}
	}()
}

huangapple
  • 本文由 发表于 2016年8月24日 18:06:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/39120284.html
匿名

发表评论

匿名网友

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

确定