在Go中处理错误

在Go中处理错误,go,error-handling,Go,Error Handling,我已经和围棋一起工作了一段时间,还没有真正弄清楚我是如何处理错误的 即使是标准库也有许多不同的方法来处理错误(有些方法甚至无法在不必求助于字符串匹配的情况下检查错误) 我最近读了戴夫·切尼的博客文章。这听起来是朝着正确的方向迈出的一步,但我仍然很难真正将其付诸实践 假设我制作了一个包a,它向第三方RESTAPI(例如Facebook Graph)发出请求。我希望这个包公开与API匹配的函数,比如说GetUser 调用GetUser会产生很多结果: 成功 由于请求失败(如第三方API关闭)而失败

我已经和围棋一起工作了一段时间,还没有真正弄清楚我是如何处理错误的

即使是标准库也有许多不同的方法来处理错误(有些方法甚至无法在不必求助于字符串匹配的情况下检查错误)

我最近读了戴夫·切尼的博客文章。这听起来是朝着正确的方向迈出的一步,但我仍然很难真正将其付诸实践

假设我制作了一个包
a
,它向第三方RESTAPI(例如Facebook Graph)发出请求。我希望这个包公开与API匹配的函数,比如说
GetUser

调用
GetUser
会产生很多结果:

  • 成功
  • 由于请求失败(如第三方API关闭)而失败
  • 第三方API返回错误(如找不到用户)
  • 响应或类似响应的反序列化失败
  • 在第二种情况下,为行为断言错误非常有效。然而,它在区分第三和第四种情况方面存在不足

    我当前的用例是实现我自己的RESTAPI,它使用第一个包。在这种情况下,我希望能够对可能的结果分别返回
    200 OK
    503服务不可用
    400错误请求
    500内部服务器错误
    响应


    解决这个问题的一个好的通用方法是什么,而不必包括从包
    a
    返回http响应代码或类似代码?

    我要做的是定义一些“包装错误”,以指示错误实际发生的位置。例如

    type SerializationError struct { Error error }
    func (err SerializationError) Error() string { return err.Error.Error() }
    
    type HTTPError struct { Error error }
    // ...
    
    然后在API客户端的代码中:

    b, err := json.Marshal(v)
    if err != nil {
         return nil, SerializationError{err}
    }
    
    // ...
    
    resp, err := client.Post(url, ct, body)
    if err != nil {
        return nil, HTTPError{err}
    }
    
    然后,您可以执行以下操作:

    err := client.GetUser(id)
    switch err.(type) {
    case SerializationError:
        // respond with 400
    case HTTPError:
        // respond with 500
    // etc.
    }
    

    在使用了一段时间后,我没有找到一个感觉恰到好处的解决方案,我开始接受没有一个好的解决方案

    我想这也可能意味着:

    然而,我已经得出结论,没有单一的方法来处理错误

    由于依赖性挑战带来的问题,我仍然希望避免类型断言错误,因此我引入了一种类似于链接文章中提到的
    临时()bool
    模式的
    内部()bool
    行为

    这至少允许我断言行为,而不必强制导入最初创建错误的包

    这不是最合适的,但现在必须这样


    Ainar-G的也值得一看。

    Dave Cheney关于错误的另一个有趣的观点。是的,请阅读John s Perayil建议的相关文章:他在这方面也做得很好,但我在发布之前阅读/观看了这些文章。之所以发布这个问题,是因为我不知道如何将它们应用于所描述的问题。Dave Cheneys博客的要点是,应该避免类型断言错误。当所有不同的可能错误都需要自己的类型时,它也会快速上升,这样调用者就可以判断如何进一步处理链上的错误。