如何避免在连续错误处理中重复自己

时间:2018-05-05 05:42:18

标签: go

我对连续错误进行了以下处理:

nodes, err := model.AllNodes()
if err != nil {                           // This error handling  
    pr := progressRes{                    // is Just a copy of
        Type:        progressResponse,    // error handling
        Message:     err.Error(),         // for the next error,
        MessageType: errorMessage,        // what is the
        Progress:    100,                 // best practice
    }                                     // to avoid
    go response(ws, pr.json())            // repeating myself here
    return                                // without making the code
}                                         // complicated
links, err := model.AllLinks()
if err != nil {
    pr := progressRes{
        Type:        progressResponse,
        Message:     err.Error(),
        MessageType: errorMessage,
        Progress:    100,
    }
    go response(ws, pr.json())
    return
}

在不使代码复杂的情况下,避免在上面的代码中重复自己的最佳做法是什么?我可以考虑添加一个新的func,但我只是觉得可能有一个更好的想法,我不知道。

3 个答案:

答案 0 :(得分:1)

如果要在多个位置重复多个步骤,正确的方法是将这些步骤抽象为一个过程,这就是编程的内容。这适用于错误处理以及程序的任何其他部分。

一个选项:

func allNodesAndLinks() ([]*Node, []*Link, error) {
    nodes, err := model.AllNodes()
    if err != nil {
        return nil, nil, err
    }
    links, err := model.AllLinks()
    if err != nil {
        return nil, nil, err
    }
    return nodes, links, nil
}

// ...

nodes, links, err := allNodesAndLinks()
if err != nil {
    pr := progressRes{
        Type:        progressResponse,
        Message:     err.Error(),
        MessageType: errorMessage,
        Progress:    100,
    }
    go response(ws, pr.json())
    return
}

另一种选择:

func respondWithError(ws io.Writer, err error) {
    pr := progressRes{
        Type:        progressResponse,
        Message:     err.Error(),
        MessageType: errorMessage,
        Progress:    100,
    }
    response(ws, pr.json())
}

// ...

nodes, err := model.AllNodes()
if err != nil {
    go respondWithError(ws, err)
    return
}
links, err := model.AllLinks()
if err != nil {
    go respondWithError(ws, err)
    return
}

答案 1 :(得分:1)

您可以使用两种不同的方法; defer或者,正如您所建议的那样,使用其他功能。

Defer会像这样工作:

// All of these must be defined before we call defer.
var err error
var progressResponse string
var errorMessage string
defer func() {
    // Since the deferred function will be called even if
    // the function has completed successfully, we need to
    // check that there actually has been an error before we
    // create the error response.
    if err == nil {
        return
    }
    pr := progressRes{
        Type:        progressResponse,
        Message:     err.Error(),
        MessageType: errorMessage,
        Progress:    100,
    }
    go response(ws, pr.json())
}()
nodes, err := model.AllNodes()
if err != nil {
    // The deferred function will automatically be called here.
    return
}
links, err := model.AllLinks()
if err != nil {
    // And in every other place where the function returns.
    return
}

这里的问题是可能存在一些与变量阴影相关的陷阱。举个例子:

var err error
defer func() {
    if err != nil {
        handleError(err)
    }
}()
if a, err := doSomething(); err != nil {
    return
}

以下是概念验证on the playground

这里的问题是err子句中的if与上限范围内的a不同;如果您在较高的范围内声明=,并使用单个作业:=而不是声明func a() { links, err := b() if err != nil { pr := progressRes{ Type: progressResponse, Message: err.Error(), MessageType: errorMessage, Progress: 100, } go response(ws, pr.json()) return } } func b() ([]Link, error) { nodes, err := model.AllNodes() if err != nil { return nil, err } links, err := model.AllLinks() if err != nil { return nil, err } // you probably then do something with nodes and links? return resolveLinks(nodes, links) } ,那么works as expected。可变阴影是一个常见的陷阱,特别是对初学者而言; further reading

因此,我通常使用和推荐的方法是具有另一种功能。调用者通常只需要一个实际的返回参数,因此它通常不会变得非常复杂。

dict.update()

答案 2 :(得分:1)

我首选的方法,因为它使单元测试比其他建议更容易,将是:

func doStuff() {
    if err := doStuffWithError(); err != nil {
        pr := progressRes{
            Type:        progressResponse,
            Message:     err.Error(),
            MessageType: errorMessage,
            Progress:    100,
        }
        go response(ws, pr.json())
        return
    }
}

func doStuffWithError() error {
    nodes, err := model.AllNodes()
    if err != nil {
        return err
    }
    links, err := model.AllLinks()
    if err != nil {
        return err
    }
    // Do something with nodes and links
    return nil
}