登录
首页 >  Golang >  Go问答

Go - 如何对包装的错误类进行子类型化?

来源:stackoverflow

时间:2024-03-26 13:45:32 354浏览 收藏

Go 中如何简洁地对包装的错误类进行子类型化?原始代码中冗长的包装器结构体可通过更简单的错误处理技术简化。将错误定义为包级变量,并使用 `fmt.Errorf("%w", err)` 生成新错误,其中 `%w` 用于包装底层错误。然后,可以在无标记 `switch` 中使用 `errors.Is` 检查错误的原因,从而避免创建自定义包装器类型。

问题内容

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

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

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
}

在我的主函数中,我区分了这两个错误。

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 中执行此操作的方法。

关于如何减少混乱的任何想法?

go 演示 https://play.golang.org/p/apzhc_minyv

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


正确答案


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

  • ab 定义为包级 error 变量,以简化操作并提高性能。
  • 除非您需要以编程方式访问只能在您要包装的错误上下文中访问的值,否则您很可能不需要声明这些自定义 wrapawrapb 错误类型。相反,您可以简单地使用 the %w verb in conjunction with fmt.Errorf 生成一个包含较低级别错误的新错误值。
  • 然后,您可以在无标记 switch 中使用 errors.Is 来检查 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")
    }
}

今天带大家了解了的相关知识,希望对你有所帮助;关于Golang的技术知识我们会一点点深入介绍,欢迎大家关注golang学习网公众号,一起学习编程~

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>