Jason Zhou
Jason Zhou

Reputation: 463

convert function type in Golang

// 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:

Upvotes: 4

Views: 8578

Answers (2)

Izana
Izana

Reputation: 3105

go spec dependencies: type casting or conversion -> assignability -> type identity

  1. explicit type casting or conversion

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)
}
  1. variable assignment

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

extra words

type assertion only requires type identity. Therefore, the rule is simpler than type assignability.

Upvotes: 0

Caleb
Caleb

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:

  1. 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 binFuncs 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

Related Questions