Casting Types
From: cast.go
4 type empty interface {} 5 type example interface { 6 notImplemented() 7 } 8 9 func main() { 10 one := 1 11 var i empty = one 12 var float float32 13 float = float32(one) 14 switch i.(type) { 15 default: 16 fmt.Printf("Type error!\n") 17 case int: 18 fmt.Printf("%d\n", i) 19 } 20 fmt.Printf("%f\n", float) 21 // This will panic at run time 22 var e example = i.(example) 23 fmt.Printf("%d\n", e.(empty).(int)) 24 }
Unlike C, Go does not allow implicit casting. This is not laziness on the part of the implementors: implicit casting makes it easy for very subtle bugs to slip into code. I recently had to find a bug in some code that had gone undetected for several years, where an implicit cast meant that a value was incorrectly initialized. The code looked correct, until you checked the type declarations of everything involved, which were spread over multiple files.
This is another example of the Go philosophy. You should never need to state the obvious to the compiler, but you should always have to explicitly specify things that are otherwise ambiguous.
The example at the start of this section shows several casts. The concept of casting in other languages is embodied by two concepts in Go. The first is type conversion; the second is type assertion.
A type conversion is similar to a cast in C. It reinterprets the value as a new type. The conversion from int to float32 is an example of this. The resulting value is a new floating-point value with the same value as the integer. In some cases, the conversion is only approximate. For example, a conversion in the other direction will result in truncation. A type conversion from an integer to a string type will return a single-character string interpreting the integer as a unicode value.
Type assertions are more interesting. They do not convert between types; they simply state to the compiler that the underlying value has the specified type. This assertion is checked at run time. If you try running this example, you will see that it aborts with a runtime panic.
This is because of the type assertion telling the compiler that the type of i is something that implements the example interface. In fact, the underlying type is int, which does not implement the notImplemented() method that this interface specifies. The type check fails on the type assertion. If you come from C++, you can think of type assertions as roughly equivalent to a dynamic_cast that throws an exception2 on failure.
Output from: cast.go
1 1 2 1.000000 3 panic: interface conversion: int is not main. example: missing method notImplemented 4 5 goroutine 1 [running]: 6 main.main() 7 /Users/theraven/Documents/Books/GoPhrasebook/ startsnippets/cast.go:22 +0x20d 8 9 goroutine 2 [syscall]: 10 created by runtime.main 11 /Users/theraven/go/src/pkg/runtime/proc.c:219 12 exit status 2
The final cast-like construct in Go is the type switch statement. This is written like a normal switch statement, but the switch expression is a type assertion to type and the cases have type names, rather than values.
The type switch in the example is used as a simple type check, like a C++ dynamic_cast.
It is more common to use type switches when defining generic data structures (see Chapter 4, Common Go Patterns) to allow special cases for various types.