Go - 如何子类型化包装错误类?

我正在包装错误(以添加上下文),然后区分两个错误。这是我目前用于测试的场景。 (函数是否正确识别错误?)我的问题是如何减少冗长。

我有两个函数会产生不同的错误:

func a() error {
    return errors.New("a")
}

func b() error {
    return errors.New("b")
}

它们都被传播错误的第三个函数调用。

func doStuff() error {
    err := a()
    if err != nil {
        return WrapA{err}
    }
    err = b()
    if err != nil {
        return WrapB{err}
    }
    return nil
}

在我的 main 函数中,我区分了这两种错误。

func main() {
    fmt.Println("Hello, playground")
    err := doStuff()
    
    switch err.(type) {
        case WrapA:
            fmt.Println("error from doing a")
        case WrapB: 
            fmt.Println("error from doing b")
        case nil:
            fmt.Println("nil")
        default:
            fmt.Println("unknown")
    }
}

到目前为止,还不错。不幸的是,要实现 WrapAWrapB,我需要大量代码:

type WrapA struct {
    wrappedError error
}

func (e WrapA) Error() string {
    return e.wrappedError.Error()
}

func (e WrapA) Unwrap() error {
    return e.wrappedError
}

type WrapB struct {
    wrappedError error
}

func (e WrapB) Error() string {
    return e.wrappedError.Error()
}

func (e WrapB) Unwrap() error {
    return e.wrappedError
}

在其他语言中,我会创建一个单一的 Wrap 结构并让 WrapAWrapB 继承自 Wrap .但我看不到在 Go 中执行此操作的方法。

关于如何减少困惑有什么想法吗?

去 Playground https://play.golang.org/p/ApzHC_miNyV

编辑: 看到j​​ub0bs的回答后,我想澄清一下: a()b() 都是我无法控制的回调。他们可能会返回各种错误。这就是我包装它们的原因。

最佳答案

如果我对问题的理解正确,你确实可以简化事情:

  • ab 定义为包级 error 变量,以简化操作并提高性能。
  • 除非您需要以编程方式访问只能在您包装的错误上下文中访问的值,否则您很可能不需要声明这些自定义 WrapAWrapB错误类型。相反,您可以简单地使用 the %w verb in conjunction with fmt.Errorf产生一个新的错误值来包装较低级别的错误。
  • 然后您可以使用 errors.Is在无标记的 switch 中检查 doStuff 函数返回的更高级别错误的原因。

( Playground )

package main

import (
    "errors"
    "fmt"
)

var (
    a = errors.New("a")
    b = errors.New("b")
)

func doStuff() error {
    err := a
    if err != nil {
        return fmt.Errorf("%w", err)
    }
    err = b
    if err != nil {
        return fmt.Errorf("%w", err)
    }
    return nil
}

func main() {
    fmt.Println("Hello, playground")
    switch err := doStuff(); {
    case errors.Is(err, a):
        fmt.Println("error from doing a")
    case errors.Is(err, b):
        fmt.Println("error from doing b")
    case err == nil:
        fmt.Println("nil")
    default:
        fmt.Println("unknown")
    }
}

https://stackoverflow.com/questions/69121476/

相关文章:

flutter - 如何在 flutter 中的行之间写 OR

docker - 使用 deps.edn 在容器中安装依赖项

c# - 如何在 C# 中使用预处理器指令仅在 Windows 10 上执行一些代码?

c++ - 在 constexpr 分支中使用枚举类值

c++ - 在 "Effective Modern C++"示例中在索引运算符之前使用 std::f

c - 有没有办法从未知字节设置/清除位,同时保持所有其他位不变?

c# - Parallel.Foreach 和每个产生不同的结果 : Why is my code

python - AES CTR解密: Cryptography and Cryptodome gi

r - 如何根据列中的两个值过滤行?

amazon-web-services - 带有自定义 SAML 应用程序的 AWS SSO 'no