【问题标题】:Return error from deferred function when error is already returned当错误已经返回时,从延迟函数返回错误
【发布时间】:2019-09-20 10:39:06
【问题描述】:

更新:我认为现在这个问题没有普遍的答案。我们可以使用答案中解释的技术返回这两个错误。我认为这里最重要的是不要忘记我们有两个错误的情况并以某种方式处理它。

注意:关于如何从延迟函数返回错误有很多关于 SO 的问题。这不是这里的问题。

(在 Go 中)当函数已经返回错误时,从延迟函数返回错误的正确方法是什么。对于example

func errorMaker() (err error) {
    defer func() {
        err = errors.New("Deferred error")
    }()

    err = errors.New("Some error")
    return
}
func main() {
    err := errorMaker()
    fmt.Printf("Error: %v\n", err)
}

在上面的代码中,延迟函数返回的错误覆盖了函数返回的错误。返回两个错误的规范方法是什么?如果另一个程序员使用我的函数,当函数返回“两个错误”时,她会从函数中得到什么结果?

我应该为此使用Error wrapping 吗?

补充说明:

  1. 正如@Volker 在他的评论中所说,我为此错误编写了一些特定于应用程序的处理。因为我知道根据错误的性质应该做什么。
  2. 我想我的问题是 - 如果我想从函数中返回所有错误,在我的场景中将它们组合起来的最佳方法是什么?

【问题讨论】:

  • 根本没有统一的通用答案。这完全取决于你的问题。甚至可能需要返回两个错误(尽管 非常 不太可能)或一个带有两个潜在错误的错误或中止程序(而不返回)或返回第一个或第二个或二进制文件或两者.没人知道。
  • @Volker 感谢您的回复!是的,这真的取决于应用程序。无论如何,我认为应该有一些共同的方法来解决这类问题。这就是为什么我问是否有人在 Go 编程方面比我更有经验,可以分享他们是如何做到这一点的。完美的团队成员致力于 Go 2.0 带来的新的 Go 错误处理。我不想自己发明一些东西,而是应用一些常见的做法。
  • Go 2 还很遥远。不要指望它喷气机有什么。现在不要计划使用可能会出现或不会出现的东西。可能没有 Go 2。更有经验的建议是:处理错误必须如何完成。在 finally 块中处理错误也是如此:没有人可以告诉你:“在任何 finally 块中处理所有这样的错误,因为......”

标签: go


【解决方案1】:

免责声明:我不知道以下建议是否可以被视为“标准”或“广泛接受”。

我应该为此使用错误包装吗?

简短回答:是的(我会这样做)。


转到 1.12 及更早版本

当我需要我的错误来传达某些特定含义时,我会做什么,而不是前面提到的error 接口,我创建了一个实现错误接口的包装器 - Error() string -。这个包装器包含我需要的所有额外信息。

如果调用者知道这些额外信息的存在,它可以通过强制转换解开错误并找到这些信息。 额外的好处是,不知情的调用者可以将错误作为通用 error 处理。

type MyError struct {
    DeferredError error
}

// Implements 'error' interface
func (e MyError) Error() string {
    // format to string
}

func someFunc() error {
    // might return an instance of MyError
}

...

// Caller code
err := someFunc()
if err != nil {
    if myErr, ok := err.(*MyError); ok {
        // here you can access the wrapped info
        fmt.Println(myErr.DeferredError)

    } else {
        // otherwise handle the error generically
    }
}


从 1.13 开始

使用 Go.13,您可以使用 errors.As 解开错误。来自官方文档:

[方法] As 找到 err 链中与 target 匹配的第一个错误,如果是,则将 target 设置为该错误值并返回 true。该链由 err 本身和通过重复调用 Unwrap 获得的错误序列组成。

var myErr *MyError
if errors.As(err, &myErr) {
    // here you can access the wrapped info
    fmt.Println(myErr.DeferredError)
} else {
    // otherwise handle the error generically 
}

正如文档所说,myErr 变量被填充为调用 As 的副作用。

【讨论】:

  • Go 1.13(errors 包)的标准库中添加了此错误包装,因此现在不需要自定义包装(如您的 MyError.DeferredError)。
猜你喜欢
  • 2010-09-22
  • 1970-01-01
  • 2011-09-14
  • 1970-01-01
  • 2015-12-28
  • 1970-01-01
  • 2023-03-08
  • 2021-04-26
  • 1970-01-01
相关资源
最近更新 更多