Go语言 是否有标准的方法来对自定义错误类型进行分类

oyxsuwqo  于 2022-12-07  发布在  Go
关注(0)|答案(1)|浏览(166)

是否有一个可接受的模式将自定义错误类型分组在一起,以便我可以根据它们的分组来不同地处理它们?
例如,下面是我在C#中使用异常时会做的事情:

abstract class FriendlyException : ApplicationException {
    protected FriendlyException(string message) : base(message) { }
}
class MyNiceException : FriendlyException {
    public MyNiceException(string message) : base(message) { }
}

然后,我可以在catch中做一些不同的事情,这取决于它是否福尔斯该类别:

try { DoSomething(); }
catch (FriendlyException ex) { Console.WriteLine(ex.Message); }
catch { Console.WriteLine("Unhandled error"); }

在Go语言中,我可以直接在类型上使用As或switch,但由于存在隐式接口,我认为这样做会浪费一个接口成员,如下所示:

type FriendlyError interface { SomeWastedMethod() }
type MyFriendlyError struct {}
func (fe MyFriendlyError) SomeWastedMethod() {}
func (fe MyFriendlyError) Error() string { return "implementing error interface" }

然后,我可以检查该组是否有如下错误:

var fe FriendlyError
err := DoSomething()
if err != nil {
    if errors.As(err, &fe) {
        fmt.Println(err.Error())
    } else {
        fmt.Println("Unhandled error")
    }
}

MyFriendlyError结构体中浪费的方法是困扰我的问题。这是实现这一点的唯一方法吗?还是有其他标准模式?
在我的示例中,我希望有多个不同的错误类型,其中一些类型可以安全地将消息返回给调用者,而其中一些类型我希望只向调用者提供一个通用消息,同时仍然保留内部日志记录的详细信息。

9gm1akwq

9gm1akwq1#

我建议如下方式:

package main

import (
    "errors"
    "fmt"
)

var (
    ErrInvalidMsg   = errors.New("invalid message")
    ErrInvalidParam = errors.New("invalid param")
    ErrBadMsg       = errors.New("bad message")
)

type GroupError1 struct {
    Base error
}

func (ge GroupError1) Error() string {
    return ge.Base.Error()
}

type GroupError2 struct {
    Base error
}

func (ge GroupError2) Error() string {
    return ge.Base.Error()
}

func TheError(n int) error {
    switch n % 3 {
    case 0:
        return GroupError2{
            Base: ErrBadMsg,
        }
    case 1:
        return GroupError1{
            Base: ErrInvalidParam,
        }
    case 2:
        return GroupError1{
            Base: ErrInvalidMsg,
        }
    }

    return nil
}

func main() {
    if err := TheError(1); err != nil {
        var ge1 GroupError1
        var ge2 GroupError2

        if ok := errors.As(err, &ge1); ok {
            fmt.Println("error group 1")
        } else if ok := errors.As(err, &ge2); ok {
            fmt.Println("error group 2")
        } else {
            fmt.Println("no error group")
        }
    }
}

这里我定义了两个错误组,因此我们可以使用errors.As检测它们,并且您不需要定义任何未使用的接口,但是您需要手动创建它们,并且没有任何自动分组。

相关问题