Reputation: 23749
Relevant code:
type somethingFuncy func(int) bool
func funcy(i int) bool {
return i%2 == 0
}
var a interface{} = funcy
func main() {
_ = a.(func(int) bool) // Works
fmt.Println("Awesome -- apparently, literally specifying the func signature works.")
_ = a.(somethingFuncy) // Panics
fmt.Println("Darn -- doesn't get here. But somethingFuncy is the same signature as func(int) bool.")
}
The first cast works, by explicitly declaring the type. But the second cast panics. Why? Is there a clean way to cast to a longer func signature?
Upvotes: 74
Views: 85539
Reputation: 441
With type assertions in Go 1.9, you can simply add =
where you define the type.
type somethingFuncy = func(int) bool
This tells the compiler that somethingFuncy
is an alternate name for func(int) bool
.
Upvotes: 34
Reputation: 2847
I believe that type alias is what you want. Proposal is accepted and should be in Go 1.9. Ie.
TypeSpec = identifier [ "=" ] Type .
References
https://github.com/golang/go/issues/18130
https://github.com/golang/proposal/blob/master/design/18130-type-alias.md
Upvotes: 2
Reputation: 57639
For type assertions (which you use) only the actual type matters. So somethingFuncy
is only equal to somethingFuncy
and not to func(int) bool
.
To start with, this has nothing to do with casting. There is no casting in go. There are type assertions and type conversions.
You're dealing with a type assertion and are assuming that the same conditions hold as for type conversions. I made the same mistake while reading your question but actually there is a huge difference in behaviour.
Suppose you have two types, say int
and type MyInt int
. These are convertible as they both
share the same underlying type (one of the conversion rules), so this works (play):
var a int = 10
var b MyInt = MyInt(a)
Now, suppose a
is not of type int
but of type interface{}
(play):
var a interface{} = int(10)
var b MyInt = MyInt(a)
The compiler will tell you:
cannot convert a (type interface {}) to type MyInt: need type assertion
So now we're not doing conversions anymore but assertions. We need to do this (play):
var a interface{} = int(10)
var b MyInt = a.(MyInt)
Now we have the same problem as in your question. This assertion fails with this panic:
panic: interface conversion: interface is int, not main.MyInt
The reason for this is stated in the type assertions section of the spec:
For an expression x of interface type and a type
T
, the primary expressionx.(T)
asserts thatx
is notnil
and that the value stored inx
is of typeT
. The notationx.(T)
is called a type assertion. More precisely, ifT
is not an interface type,x.(T)
asserts that the dynamic type ofx
is identical to the typeT
.
So int
must be identical to MyInt
. The rules of type identity state that
(amongst other rules):
Two named types are identical if their type names originate in the same TypeSpec.
As int
and MyInt
have different declarations (TypeSpecs) they're not equal
and the assertion fails. When you assert a
to int
, the assertion works.
So what you're doing is not possible.
The actual check happens in this code, which simply checks if both types are the same, as expected.
Upvotes: 96
Reputation: 2028
Just to complete nemo's awesome answer, note that while you can't jump directly from an interface (e.f., interface{}
) of a given dynamic type (e.g., int
) to another type (e.g., type MyInt int
), you can do the two steps one after the other:
Note that since the underlying type is, as its name implies, dynamic, it's a good idea to test if the type assertion succeeded or failed. On the other hand, the type conversion correctness is enforced by the compiler.
Here is your playground snippet slightly modified: http://play.golang.org/p/FZv06Zf7xi
Upvotes: 8