Home  >  Article  >  Backend Development  >  Concrete type error snippet in Golang

Concrete type error snippet in Golang

PHPz
PHPzforward
2024-02-05 22:12:12960browse

Golang 中具体类型的错误片段

Question content

I am trying out error wrapping in go and have a function that returns a wrapped custom error type. What I want to do is iterate over a list of expected errors and test whether the function's output contains these expected errors.

I found that putting the custom error into []error means that the type of the custom error will be *fmt.wraperror, which means errors.as( ) almost always returns true.

As an example, consider the following code:

package main

import (
    "errors"
    "fmt"
)

type anothererror struct {
}

func (e *anothererror) error() string {
    return "another error"
}

type missingattrerror struct {
    missingattr string
}

func (e *missingattrerror) error() string {
    return fmt.sprintf("missing attribute: %s", e.missingattr)
}

func dosomething() error {
    e := &missingattrerror{missingattr: "key"}
    return fmt.errorf("dosomething(): %w", e)
}

func main() {
    err := dosomething()
    expectederrone := &missingattrerror{}
    expectederrtwo := &anothererror{}
    expectederrs := []error{expectederrone, expectederrtwo}

    fmt.printf("is err '%v' type '%t'?: %t\n", err, expectederrone, errors.as(err, &expectederrone))
    fmt.printf("is err '%v' type '%t'?: %t\n", err, expectederrtwo, errors.as(err, &expectederrtwo))

    for i := range expectederrs {
        fmt.printf("is err '%v' type '%t'?: %t\n", err, expectederrs[i], errors.as(err, &expectederrs[i]))

    }
}

The output is

is err 'dosomething(): missing attribute: key' type '*main.missingattrerror'?: true
is err 'dosomething(): missing attribute: key' type '*main.anothererror'?: false
is err 'dosomething(): missing attribute: key' type '*fmt.wraperror'?: true
is err 'dosomething(): missing attribute: key' type '*fmt.wraperror'?: true

Ideally I would like the output to be

Is err 'DoSomething(): missing attribute: Key' type '*main.MissingAttrError'?: true
Is err 'DoSomething(): missing attribute: Key' type '*main.AnotherError'?: false
Is err 'DoSomething(): missing attribute: Key' type '*main.MissingAttrError'?: true
Is err 'DoSomething(): missing attribute: Key' type '*main.AnotherError'?: false

The reason for the error is that I want to be able to define a list of expected errors for each test case entry. Suppose I know that providing certain inputs to a function will cause it to follow a path and return errors containing a specific error.

How do I convert the *fmt.wraperror type from the []error slice back to the original type so that I can use it with error.as?

I know I can use to cast it to a specific type. (anothererror), but in order to make it work when iterating over slices, I have to do this for every possible error the function might return, no? )


Correct answer


You can cheat using the following method errors.as:

func main() {
    err := DoSomething()
    m := &MissingAttrError{}
    a := &AnotherError{}
    expected := []any{&m, &a}

    for i := range expected {
        fmt.Printf("Is err '%v' type '%T'?: %t\n", err, expected[i], errors.As(err, expected[i]))
    }
}

The type printed is not what you expect, but errors.as works as it should.

The reason your example doesn't work is that what you're passing to errors.as is *error. Therefore, the wrapped error value (i.e. err) is assigned directly to the target value. In my example, the value passed to errors.as is **anothererror, and err is not assignable to *anothererror.

The above is the detailed content of Concrete type error snippet in Golang. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete