error
is an interface:
type error interface {
Error() string
}
This means that any type which has a method: Error() string
fulfills the interface and can be assigned to a variable of type error
.
binFunc
has such a method:
func (f binFunc) Error() string {
return "binFunc error"
}
New developers in Go sometimes find this confusing because they don't realize it's possible to attach methods to more than just structs. In this case binFunc
is defined liked this:
type binFunc func(int, int) int
So the way this works is you are allowed to convert any function which has the same signature: (from the spec)
A function type denotes the set of all functions with the same parameter and result types.
So if you create a function add
:
func add(x, y int) int {
return x + y
}
You are allowed to convert this into a binFunc
:
binFunc(add)
And because of the Error
method on binFunc
we defined above, we are then able to assign this new binFunc
to a variable of type error
:
var err error
var bf binFunc = binFunc(add)
err = bf
fmt.Println
's behavior is to call .Error()
on errors for you:
- If an operand implements the error interface, the Error method will be invoked to convert the object to a string, which will then be formatted as required by the verb (if any).
So to answer your questions:
- The
Error
method is executed because fmt.Println
looks for arguments of type error
, invokes .Error()
and prints the resulting string.
- You are allowed to assign
binFunc
s to err
because binFunc
has an Error
method. You cannot assign add
directly to err
because it does not have an Error
method. But you are allowed to convert add
to a binFunc
because they have the same function signature, and by doing so you can then assign it to the err
variable.