I noticed that Go assertion doesn't work as I expect for zero int. Here is the code:
var i interface{}
i = 0
i32, ok := i.(int32)
fmt.Println(ok)
fmt.Println(i32)
The output is following:
false
0
I can't find an explanation of this behavior. Is it a bug?
No, it's not a bug, it's a well defined behavior.
This line:
i = 0
Is an assignment, and you use the untyped 0
integer constant to assign to i
. Since a (concrete) type is needed to carry out the assignment (and i
s type being interface{}
does not define one), the default type of that untyped constant will be used which is int
. Read The Go Blog: Constants:
The answer is that an untyped constant has a default type, an implicit type that it transfers to a value if a type is needed where none is provided.
You can verify it if you modify it like this:
i2, ok := i.(int)
fmt.Println(ok)
fmt.Println(i2)
Which outputs:
true
0
If you would use a typed constant:
i = int32(0)
Then yes, the stored value would be of type int32
, and you would get the same output:
i = int32(0)
i32, ok := i.(int32)
fmt.Println(ok)
fmt.Println(i32)
Try the examples on the Go Playground.
i
doesn't contain an int32
, it contains an int
, and so the type assertion fails.
Assigning a literal value directly to an interface{}
like this or using one in a short variable declaration can be a bit confusing because you don't really get to see what type of value you get; you need to know the rules for the "default type" of a constant. If this gives you trouble, you can explicitly cast it to a type, like i = int32(0)
, which will ensure that i
does in fact contain an int32
.