ARTICLES
Reflect in go
By me
Which paradigm is Go, actually?
Properties in languages is like music genre. You will rarely find some band that is only one genre and nothing else. It’s same in computer science - the term “static” or “dynamic” is more and more blurry, like CPU architecture (RISC, CISC). Also many support both OOP and functional, for example. If you believe wikipedia https://en.wikipedia.org/wiki/Go_(programming_language) then go is multi-paradigm which i actually agree with. But typing discipline is static, strong, inferred and structural. How does this works with multi-paradigm? Sounds like a trouble - well, not really, Java has it for example.
What is a reflection?
Reflection is often associated with dynamic language as said before and if we get definition it says: reflection typically involves analysis of the types and metadata of generic or polymorphic data
. It’s actually able to read code as data and use that data later in code. Not all languages support reflection and each that does implements it differently. This can cause some confusion as you would expect something to be used in a same way, but it’s actually not. And golang is no different than others - coders use it to inspect, modify and create variables, functions and structs.
How to use it?
Go support dynamic typing like :=
and variable gets type that is returned from expression so compiler knows type during compile-time. What if we want to know which type this dynamic variable got?
Consider this example:
package main
import (
"fmt"
"reflect"
)
func main() {
s := []string{"apple", "oranges"}
sType := reflect.TypeOf(s)
fmt.Println(sType)
}
This returns []string
which is correct type that is evaluated at s := []string{"apple", "oranges"}
.
There is a way to get primitive type of which variable is made of.
It’s really like base type of variable and it’s get by calling Kind()
method like this:
package main
import (
"fmt"
"reflect"
)
func main() {
s := []string{"apple", "oranges"}
sType := reflect.TypeOf(s)
fmt.Println(sType.Kind())
}
This returns: slice
which actually IS slice. The values can be a slice, a map, a pointer, a struct, an interface, a string, an array, a function, an int or some other primitive type. Any custom type that is based on primitive will have that primitive as Kind(). This very useful information can be used later on in code to do decision based on type. For example let’s say you get some data that is imported into go code. Data is imported based on import type but it can be anything. So you want to treat imported data differently based on type and this is where reflection really shines.
Go does not have generics (like Java for example) but it does have interface{} type. In interface{} type there’s no hidden variable type as type is lost, all you can do is treat interface{} variable as casting it to some other type. Actual type of interface{} is interface{}. But all types satisfy interface{} type, so all of them have implemented interface{}. If some variable is passed as interface{} you can use reflection to get it’s type:
package main
import (
"fmt"
"reflect"
)
func getType(in interface{}) {
inType := reflect.TypeOf(in)
inValue := reflect.ValueOf(in)
fmt.Println("Type of 'in': ", inType)
fmt.Println("Value of 'in': ", inValue)
}
func main() {
var x int = 1
getType(x)
}
This returns:
Type of 'in': int
Value of 'in': 1
You can also use reflection to make slices. This example takes slice type and creates new one with reflect.MakeSlice:
package main
import (
"reflect"
"fmt"
)
func main() {
intSliceReflect := reflect.MakeSlice(reflect.TypeOf(make([]int, 0)), 0, 0)
fmt.Println(intSliceReflect)
}
Well, i hope you find this useful in your project, and remember - using reflect means you really know what you are doing. If you don’t you’ll get panic and there’s no compiler warning to protect you from this. Good idea would be to make trough test when you use reflect. If you are using it in some interesting way i would like to know, so please write me in the comment section below.