Reputation: 463
// Each type have Error() string method.
// The error built-in interface type is the conventional interface for
// representing an error condition, with the nil value representing no error.
// type error interface {
// Error() string
// }
func (f binFunc) Error() string {
return "binFunc error"
}
func func_type_convert() {
var err error
err = binFunc(add)
fmt.Println(err)
fmt.Println(i)
}
I have two questions about the code above:
Error
method executed, when add
function was converted into binFunc
type?add
function converted result was able to assign to an err error interface variable?Upvotes: 4
Views: 8578
Reputation: 3105
go spec dependencies: type casting or conversion -> assignability -> type identity
binFunc
and func(int, int) int
have same underlying representation.
binFunc(add)
note, type casting can happen between 2 types that have the same underlying representation. However, their type can be totally different.
type MyInt int
func main() {
var b MyInt = 3
a := int(b)
fmt.Println(a, b)
}
check type identity
based on type identity rule, binFunc
is identical to func(int, int) int
. So you can do type casting as below:
A named type is always different from any other type. Otherwise, two types are identical if their underlying type literals are structurally equivalent; that is, they have the same literal structure and corresponding components have identical types.
func(int, int) int
is type literal, and it's unnamed.
type binFunc func(int, int) int
is a named type.
Predeclared types, defined types, and type parameters are called named types. An alias denotes a named type if the type given in the alias declaration is a named type.
named type is different from others. but here, binFunc
is compared with the un-named type: their underlying type literals are structurally equivalent, both func(int, int) int
.
var bfunc binFunc = add
check assignability
variable of named type can be assigned with a value of unnamed type providing their underlying type is identical.
You may call this an implicit type conversion here, but it's not accurate. At least golang doesn't call this type conversion because the underlying type/representation is the same.
inspired by this answer
type assertion only requires type identity. Therefore, the rule is simpler than type assignability.
Upvotes: 0
Reputation: 9458
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:
Error
method is executed because fmt.Println
looks for arguments of type error
, invokes .Error()
and prints the resulting string. 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.Upvotes: 13