douzhuijing4911 2013-09-12 18:16
浏览 24
已采纳

避免检查错误是否为零重复?

I'm currently learning go and some of my code looks like this:

a, err := doA()
if err != nil {
  return nil, err
}
b, err := doB(a)
if err != nil {
  return nil, err
}
c, err := doC(b)
if err != nil {
  return nil, err
}
... and so on ...

This looks kinda wrong to me because the error checking takes most of the lines. Is there a better way to do error handling? Can I maybe avoid this with some refactoring?

UPDATE: Thank you for all the answers. Please note that in my example doB depends on a, doC depends on b and so on. Therefore most suggested refactorings don't work in this case. Any other suggestion?

  • 写回答

6条回答 默认 最新

  • dongya0914 2013-09-12 18:53
    关注

    This is a common complaint, and there are several answers to it.

    Here are a few common ones:

    1 - It's not so bad

    This is a very common reaction to these complaints. The fact you have a few extra lines of code in your code is not in fact so bad. It's just a bit of cheap typing, and very easy to handle when on the reading side.

    2 - It's actually a good thing

    This is based on the fact that typing and reading these extra lines is a very good reminder that in fact your logic might escape at that point, and you have to undo any resource management that you've put in place in the lines preceding it. This is usually brought up in comparison with exceptions, which can break the flow of logic in an implicit way, forcing the developer to always have the hidden error path in mind instead. Some time ago I wrote a more in-depth rant about this here.

    3 - Use panic/recover

    In some specific circumstances, you may avoid some of that work by using panic with a known type, and then using recover right before your package code goes out into the world, transforming it into a proper error and returning that instead. This technique is seen most commonly to unroll recursive logic such as (un)marshalers.

    I personally try hard to not abuse this too much, because I correlate more closely with points 1 and 2.

    4 - Reorganize the code a bit

    In some circumstances, you can reorganize the logic slightly to avoid the repetition.

    As a trivial example, this:

    err := doA()
    if err != nil {
        return err
    }
    err := doB()
    if err != nil {
        return err
    }
    return nil
    

    can also be organized as:

    err := doA()
    if err != nil {
        return err
    }
    return doB()
    

    5 - Use named results

    Some people use named results to strip out the err variable from the return statement. I'd recommend against doing that, though, because it saves very little, reduces the clarity of the code, and makes the logic prone to subtle issues when one or more results get defined before the bail-out return statement.

    6 - Use the statement before the if condition

    As Tom Wilde well reminded in the comment below, if statements in Go accept a simple statement before the condition. So you can do this:

    if err := doA(); err != nil {
        return err
    }
    

    This is a fine Go idiom, and used often.

    In some specific cases, I prefer to avoid embedding the statement in this fashion just to make it stand on its own for clarity purposes, but this is a subtle and personal thing.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(5条)

报告相同问题?

悬赏问题

  • ¥15 优质github账号直接兑换rmb,感兴趣伙伴可以私信
  • ¥15 错误(10048): “调用exui内部功能”库命令的参数“参数4”不能接受空数据。怎么解决啊
  • ¥15 安装svn网络有问题怎么办
  • ¥15 Python爬取指定微博话题下的内容,保存为txt
  • ¥15 vue2登录调用后端接口如何实现
  • ¥65 永磁型步进电机PID算法
  • ¥15 sqlite 附加(attach database)加密数据库时,返回26是什么原因呢?
  • ¥88 找成都本地经验丰富懂小程序开发的技术大咖
  • ¥15 如何处理复杂数据表格的除法运算
  • ¥15 如何用stc8h1k08的片子做485数据透传的功能?(关键词-串口)