如何将不同的错误接口实现存储在一起,然后在 Go 中使用它们进行类型比较?

Posted

技术标签:

【中文标题】如何将不同的错误接口实现存储在一起,然后在 Go 中使用它们进行类型比较?【英文标题】:How can I store different error interface implementations together and then use them for type comparison in Go? 【发布时间】:2020-02-21 15:19:51 【问题描述】:

我正在尝试在 go 中编写一个表测试,其中测试用例会导致不同的错误。然后我想检查错误的类型是否与测试用例中定义的错误类型匹配,使用errors.As()。每个测试用例都由一个结构定义,因此结构中需要有一个类型可以容纳接口error 的任何实现,这也是为了验证测试中返回的类型是否正确。

我尝试过如下定义结构

type testCase struct 
        testInput string
        expectedError error

我还有一些实现error 接口的自定义错误,比如说一个叫做myCustomError

然后我像这样声明该结构的变量:

mTest := testCase
        testInput: "some failing string",
        expectedError: myCustomError,

如果我再做这样的测试......

err := someFunc(mTest.testInput)
if errors.As(err, &mTest.expectedError) 
        // test have succeeded

... if 语句将始终返回 true,无论返回哪种自定义错误类型。

我在 Go Playground 上做了一个最小的例子:https://play.golang.org/p/uMdbMvfcdQi

在操场示例中,我希望字符串“matching myError1”被打印两次,但是当值存储为普通的error 之前,它也匹配myError2,然后用于检查类型变量错误。 甚至有可能做这样的事情吗?

【问题讨论】:

这里我想你想使用errors.Is,而不是errors.As @yazgazan 是正确的,Is 是您想要的。 (play.golang.org/p/5LdhUUaZxCd) "As 依次展开它的第一个参数,寻找可以分配给它的第二个参数的错误,它必须是一个指针。如果成功,它执行分配并返回 true。" @yazgazan 如果返回的错误具有某种属性,这将不起作用,不幸的是它们在我的真实案例中具有(参见play.golang.org/p/JIsNFJ364te)它们也可能包含在其他一些错误中。我从问题中省略了这一点,以使其最小化。如果您对解决问题有一些想法,我很高兴听到它,否则将其发布为答案,我会将其标记为已解决,因为它回答了实际问题。 您可以实现Is(error) bool 方法,以便Is 适用于您的自定义类型:golang.org/pkg/errors/#Is。 如果您无法控制这些自定义错误类型,那么想到的唯一解决方案就是使用反射...... 【参考方案1】:

在测试用例中存储一个指向目标值的指针。

type testCase struct 
    testInput string
    expectedError interface


mTest := testCase
    testInput: "some failing string",
    expectedError: &myCustomError,


err := someFunc(mTest.testInput)
if errors.As(err, mTest.expectedError) 
    // test have succeeded

最小示例:https://play.golang.org/p/igJy9L_ui73

【讨论】:

以上是关于如何将不同的错误接口实现存储在一起,然后在 Go 中使用它们进行类型比较?的主要内容,如果未能解决你的问题,请参考以下文章

Go接口

贝壳Go实现的多云对接存储网关建设

确保类型在 Go 编译时实现接口

Go方法和接口

Go方法和接口

存储库、管道、业务逻辑和域模型 - 我如何将它们组合在一起?