1

I'm trying to understand golang interface, my problem is that why err2.What undefined.

Here is a simple code. The output indicates that both err and err2 have same type as *main.MyError, but err2 have no field "What", so there must be some difference between err and err2, but I cannot figure out the difference here. I just began learning golang not long before, any help will be greatly appreciated.

package main

import (
        "fmt"
        "time"
        "reflect"
)

type MyError struct {
        When time.Time
        What string
}

func (e *MyError) Error() string {
        return fmt.Sprintf("at %v, %s",
                e.When, e.What)
}

func run() error {
        return &MyError{
                time.Now(),
                "it didn't work",
        }
}

func main() {
        err := &MyError{time.Now(), "Hello"}
        fmt.Println(reflect.TypeOf(err))
        fmt.Println(err.What)   

        err2 := run()
        fmt.Println(reflect.TypeOf(err2))
        fmt.Println(err2.What)
}

expected output:

main.MyError
Hello
main.MyError
it didn't work

actual output:

\# command-line-arguments ./test.go:34:18: err2.What undefined (type error has no field or method What)

Anshu
  • 1,277
  • 2
  • 13
  • 28
Cyanic
  • 9
  • 5

2 Answers2

1

The function run() returns a value of type error, which is an interface type. Yes, it wraps a value of concrete type *MyError, but to get access to MyError's fields, you need to use a type assertion:

fmt.Println(err2.(*MyError).What)

Try it on the Go Playground.

Note that a value of error type may contain values of other concrete types, actually any that implements the error interface. If it would contain a value of another type, the above type assertion would result in a runtime panic.

If you're unsure err2 actually holds a value of type *MyError and you want to avoid the runtime panic, you may use the special form of type assertion to get this information and only act if it is so:

if myerror, ok := err2.(*MyError); ok {
    fmt.Println(myerror.What) // Here myerror has static type *MyError
} else {
    fmt.Println("Some other error:", err2)
}

Try this one on the Go Playground.

icza
  • 389,944
  • 63
  • 907
  • 827
  • Thanks, that works! So does that means the run() function just return an error type which wraps a value of *MyError instead of the &MyError written in the run function code block. – Cyanic Jul 15 '19 at 07:47
  • @Cyanic `&MyError` is not a type, it's the address operator applied on a composite literal, which results in a value of type `*MyError`. – icza Jul 15 '19 at 07:55
0

I think the interface of error type is let you use Error() method without any detail in the concrete structure. You can check on the Go Playground