How to log type assertion errors in golang?
Asked Answered
S

2

19

I have an array of some data which I want to map in []string. I can do it in 2 ways:

a)

// someData
s := someData.([]string)

In this case, the execution would stop after listing the error on the console.

b)

// someData
s, ok := someData.([]string)

In this case, no errors would occur but s will have its zero-value


I want to log the errors in such type assertion failure cases without stopping the execution. However, when I am using type (b), I cannot see the error details.

The only solution I can think is to use reflect.TypeOf and print both the types.

Is there any other way we can get the error when using solution (b)?

Shellans answered 3/6, 2016 at 8:39 Comment(0)
H
30

You can construct the log message yourself. There's no need for explicit calls to reflect as there's a printf format string %T that produces the type.

s, ok := someData.([]string)
if !ok {
    log.Printf("got data of type %T but wanted []string", someData)
    ... handle the failure somehow
}

Without knowing the context it's hard for me to produce a useful and informational log statement, but you can adapt the idea to suit your use case.

Hairdresser answered 3/6, 2016 at 8:52 Comment(3)
Surprising that golang doesn't require checking that the type assertion is valid. Couldn't failing to check the validity of the type assertion lead to runtime errors?Wiry
@Wiry the ok value says whether the type assertion is valid.Hairdresser
Right, and when dealing with imported data such as a config file, or json - its possible that when you assert types you will fail. If your type assertion fails without checking its validity what happens?Wiry
A
4

Well, depending on how you want to do your type assertions, there is a way of getting the errors both in case a) and b).

So, I will cover b first because if is the most straight forward: you can use the %T to get the type of the elements:

func typeAssert(i interface{}) []string {
    s, ok := i.([]string)
    if !ok {
        fmt.Printf("interface conversion: interface is %T, not []string\n", i)
    }
    return s
}

The other way involves recovering from the error, so you can get the panic message as an error:

func assertType(i interface{}) []string {

    // Recover
    defer func() {
        if err := recover(); err != nil {
            fmt.Println(err)
        }
    }()

    return i.([]string)
}

func main() {
    assertType([]int{42})

    fmt.Println("Recovered from the error")
}
// OUTPUT:
// interface conversion: interface is []int, not []string
// Recovered from the error

Of course, you can add your own treatment of the errors, depending of what you want to do. The first solution allows for more flexibility anyway, but recovermay be handy sometimes (not necessarily in this case).

Here is the link to the Go playground

Arlaarlan answered 3/6, 2016 at 9:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.