如何在Golang中处理运行时错误?

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

How to use run time error in golang?

问题

我正在尝试从3个服务器下载文件。我的想法是,如果第一个服务器关闭了,就使用第二个服务器。我注意到,如果第一个服务器关闭了,会出现运行时错误。我想知道如何利用这个错误,我需要像这样的代码:

if run time err!=nil{do something}

我是Go语言的新手,希望有人可以帮助我。谢谢。

英文:

I am trying to download something from 3 servers. My idea is if the first server is closed,it will use the second server. I noticed,if the first server has been closed, it will created a run time error.I want to know how to use this error,what i need is like this:

if run time err!=nil{do something}

i am new to golang,hope someone can help me
thank you

答案1

得分: 9

为了详细说明FUZxxl的解释,Go语言在错误(something which could go wrong indeed went wrong)和异常(something which could not possibly go wrong actually went wrong)之间进行了区分。

这种区分有时可能很微妙(因为它依赖于“意外”),但它也可以比其他语言中的“一切皆异常”更清晰。

例如,考虑可能溢出的整数。一种可能是将其视为“正常”行为,应该适当处理:

func safe_add(x, y uint32) (uint32, error) {
    z := x + y
    if z < x || z < y {
        return 0, fmt.Errorf("Integer overflow")
    }
    return z, nil
}

另一种可能是将其视为“永远不会发生”的情况,并在发生时通过运行时的panic处理:

func panic_add(x, y uint32) uint32 {
    z, err := safe_add(x, y)
    if err != nil {
        panic(err)
    }
    return z
}

(请注意,我在这里使用了自己的safe_add,但你当然不必这样做)

主要区别在于之后如何处理错误。使用error将数字相加直到溢出的示例:

func safeloop(u uint32) {
    var err error
    for {
        if u, err = safe_add(u, u); err != nil {
            fmt.Println(err)
            return
        } else {
            fmt.Println(u)
        }
    }
}

而处理panic使用了recover内置函数:

func panicloop(u uint32) {
    defer func() {
        if err := recover(); err != nil {
            fmt.Println(err)
        }
    }()
    for {
        u = panic_add(u, u)
        fmt.Println(u)
    }
}

(完整示例请参见playground

请注意,panic版本的循环要简单得多,因为你基本上不期望出现任何错误,也不会检查错误。与之相对应的是,处理panic的方式相当繁琐,即使对于像这样非常简单的示例也是如此。你可以使用defer一个函数来调用recover并捕获错误,当它出现并中断函数时。当你的代码变得更复杂时,跟踪panic发生的位置/方式并相应地采取措施可能比在可能出现错误的地方检查错误的方式要复杂得多,使用result, err := func_which_may_fail(...)模式。

你甚至可以在panic、recover返回错误、将错误转换为panic之间进行交替,但这被认为是不良设计。

关于错误处理和panic,有一些很好的资源可以在Go博客上找到。错误处理panic以及规范都是很好的阅读材料。

在你的情况下,由于你预期“服务器已关闭”是一个相当频繁的行为,你应该像FUZxxl建议的那样使用error方式,但我希望这对你(或其他人)理解Go中的错误处理方式有所帮助。

英文:

To elaborate on what FUZxxl explained, go makes a distinction between an error (something which could go wrong indeed went wrong) and an exception (something which could not possibly go wrong actually went wrong).

The distinction can sometimes be subtle (as it relies on what is 'unexpected'), but it can also be clearer than the 'everything is an exception' that you see in other languages.

For instance, consider integers which might overflow. One possibility is to consider it a 'normal' behaviour, which should be handled appropriately:

func safe_add(x, y uint32) (uint32, error) {
    z := x + y
    if z &lt; x || z &lt; y {
        return 0, fmt.Errorf(&quot;Integer overflow&quot;)
    }
    return z, nil
}

Another is to consider it 'never happens' and have the runtime panic in the unlikely case when it happens against all odds:

func panic_add(x, y uint32) uint32 {
    z, err := safe_add(x, y)
    if err != nil {
        panic(err)
    }
    return z
}

(Note that I use my own 'safe_add' here, but you don't have to of course)

The main difference is in the way you handle the error afterwards. Adding a number to itself until it overflows with errors gives:

func safeloop(u uint32) {
    var err error
    for {
        if u, err = safe_add(u, u); err != nil {
            fmt.Println(err)
            return
        } else {
            fmt.Println(u)
        }
    }
}

While handling panics uses the recover built-in function:

func panicloop(u uint32) {
    defer func() {
        if err := recover(); err != nil {
            fmt.Println(err)
        }
    }()
    for {
        u = panic_add(u, u)
        fmt.Println(u)
    }
}

(full examples on the playground)

Note that the panic version has a much simpler loop, as you basically never expect anything to go wrong and never check for errors. The counterpart for this is that the way to handle panics is quite cumbersome, even for a very simple example like this. You defer a function which will call recover and capture the error when it arises and breaks out of the function. When your code becomes more complex, tracking exactly where/how the panic arose and acting on it accordingly can become much more complex than checking for errors in places where they could arise, with the result, err := func_which_may_fail(...) pattern.

You can even alternate between panics, recover which return errors, errors converted to panics, ... but this is (understandably) considered poor design.

There are some good resources on error handling and panics on the go blog. The specs is a good read to.

In your case, as you expect 'the server is closed' to be a pretty frequent behaviour, you should definitely go the error way, as FUZxxl suggested, but I hope this might be useful to you (or others) to understand how error handling works in Go.

答案2

得分: 1

当你做一些可能出错的操作时,会得到一个error对象。

bytes, err = stream.Read(buffer)

为了检查你尝试的操作是否出错,可以将error对象与nil进行比较。nil表示没有发生错误。如果错误不是nil,你可以对其进行处理。

if err != nil {
    // 在这里处理错误
}
英文:

When you do something which could go wrong, you get an error object.

bytes, err = stream.Read(buffer)

To check whether what you tried actually went wrong, compare the error object against nil. nil signalizes that no error has happened. In the case the error is not nil, you can do something about it.

if err != nil {
    // insert error handling here
}

huangapple
  • 本文由 发表于 2013年11月12日 12:47:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/19921060.html
匿名

发表评论

匿名网友

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

确定