Do Not Confuse Type Conversion and Type Assertion
There are two ways to cast values in GoLang because GoLang is a static type language but there is an interface type for unclear types. The usage of interfaces in GoLang is a little bit tricky. An interface isn’t just a collection of method contracts. We can create a variable of its type. An interface does not have a static value, rather it points to a dynamic value. This feature provides easy programming like script languages when it is necessary. For example, we can need unclear types of function parameters. So you should use interface type on your function parameters.
func Test(v interface{}) {
…
}
I want to explain by full example code.
package main
import (
“fmt”
)
func Test(i interface{},s interface{}) {
fmt.Printf(“Type(i): %T , Type(s): %T”, i,s)
}
func main() {
Test(5, “batur”)
}
Output :
Type(i): int , Type(s): string
Parameters of the Test function is an interface type. You can give any type of value. This is called as Duck Typing.
“Duck Typing” says: If it walks like a duck, and quacks like a duck, then it must be a duck.
I should give you a piece of advice. If you don’t need Duck Typing, do not use. These approaches can make increase your runtime error.
Now you need the value of parameters. So you must use “reflect” package.
package main
import (
“fmt”
“reflect”
)func Test(i interface{},s interface{}) {
iVal := reflect.ValueOf(i)
sVal := reflect.ValueOf(s)
fmt.Printf(“Type(i): %T , Type(s): %T \n”, i,s)
fmt.Printf(“Type(iVal): %T , Type(sVal): %T \n”, iVal,sVal)
fmt.Printf(“Value(i): %v , Value(s): %v \n”, iVal,sVal)
}func main() {
Test(5, “batur”)
}
Output:
Type(i): int , Type(s): string
Type(iVal): reflect.Value , Type(sVal): reflect.Value
Value(i): 5 , Value(s): batur
You should notice that I use “%v” to print values because I have no integer and string type values. If you try using “%i”, you will get an error. I can get values by “reflect” package but generally, we need static and real type variables. For example, you want to use integer value in math operations. You cannot use iVal in math operations. You must assert to an integer.
Last version of our script:
package main
import (
“fmt”
)func Test(i interface{},s interface{}) {
var iVal int
var sVal string
iVal = i.(int)
sVal = s.(string)
fmt.Printf(“Type(i): %T , Type(s): %T \n”, i,s)
fmt.Printf(“Type(iVal): %T , Type(sVal): %T \n”, iVal,sVal)
fmt.Printf(“Value(i): %d , Value(s): %s \n”, iVal,sVal)
}func main() {
Test(5, “batur”)
}
Type(i): int , Type(s): string
Type(iVal): int , Type(sVal): string
Value(i): 5 , Value(s): batur
Now you can see real types. “iVal” is an integer and “sVal” is a string. That is the “type assertion”.
v = t.(Type) // type assertion
Type conversion is different and simple. Conversion is about change value type. There are some functions same named with the type name.
v = Type(t) // type conversion
Example :
package main
import (
“fmt”
“math”
)func main() {
var x = 3
var f float64 = math.Sqrt(float64(x))
var i uint = uint(f)
fmt.Printf(“Values: %v , %v, %v”, x, f, i)
}
Output:
Values: 3 , 1.7320508075688772, 1
If you have a string value, you cannot use “int” or “uint” functions. There is “strconv” library that Linux lovers know well. The easiest way is to use the strconv.Atoi()
function.
package main
import (
“fmt”
“strconv”
“log”
)func main() {
var s string
s = “5”
var i int
i,err := strconv.Atoi(s)
if err != nil {
log.Fatalf(“Error on conversion %s”, s)
}
fmt.Printf(“Values: %s , %d \n”, s, i)
fmt.Printf(“Types: %T , %T”, s, i)
}
Output:
Values: 5 , 5
Types: string , int
Conclusively, I can say that conversion is used when you are dealing with types, Assertion is used when you’re dealing with an interface.
Is it understandable and easy? See you later. :)