golang reflection tips

Because I’m the kind of person who likes genericity, I often find myself using features of languages that are flagged as “only use it if you know what you’re doing”. Golang reflection is one of those features, powerful yet a bit confusing.

Reflection, as explained in The Laws of Reflection is the ability of a program to examine its own structure, particularly through types; it’s a form of metaprogramming

In short, you can introspect variables at run-time, making your program exceptionally dynamic. How can this serve any purpose? well imagine for example creating function names dynamically by another function parameter. Pretty cool uh?

But first things first, let’s draw the scene, the reflect package exposes two principal functions that are used to dive into our variables, TypeOf and ValueOf. Those functions return, respectively, a reflect.Value and reflect.Type type.

Let’s start an example from there, consider a simple int variable:

1
i := 3

Here’s a reflect representation of i‘s type:

1
r := reflect.TypeOf(i)

Without any surprise, if we print it, we get int:

1
fmt.Printf("%v\n", r)

play it

Using a similar syntax, here we get the value of i:

1
r := reflect.ValueOf(i)

Which prints i’s value

Actually, you can retrieve i‘s type using the Value.Type() method:

1
fmt.Printf("%v\n", r.Type())

In the previous ValueOf example we only wanted to print i‘s value, but it turns out we also can modify it, yet we need to make a little change to the call.
When we do ValueOf(i), we actually copy i to the Value part of the reflection, so naturally, changing it would not affect the initial value of i. In fact, this would be so useless that it’s not even permitted

The error says that the value is unadressable, and this can be checked with the CanAddr method.

What we need here looks like what we would do in a C program where a function needs to modify a parameter: passing the address of the parameter, and instead of dereferencing it with a *, we’ll use the Elem() method:

1
fmt.Println(reflect.ValueOf(&i).Elem().CanAddr())

play it

Now we can modify i‘s content using the SetInt() method

Another nice trick with reflection is the ability to inspect a struct content, either by index, by field name or even by tag if the struct happens to have some.

Let’s first try a simple enumeration of a struct fields:

1
2
3
4
5
6
7
8
9
10
var s struct {
name string
id int64
}

r := reflect.TypeOf(s)

for i := 0; i < r.NumField(); i++ {
fmt.Printf("%v\n", r.Field(i))
}

As you might have guessed, r.NumField() returns the number of fields in the struct, and r.Field(i) accesses the ith field of the struct. This loop will print a StructField, which contains many informations about the field, if you only want the field’s name, simply request r.Field(i).Name.

Here’s another example using reflect ability to inspect struct tags:

1
2
3
4
5
6
7
8
9
10
11
12
var s struct {
name string `daname`
id int64 `daid`
}

r := reflect.TypeOf(s)

for i := 0; i < r.NumField(); i++ {
if r.Field(i).Tag == "daname" {
fmt.Printf("found tag for %v\n", r.Field(i).Name)
}
}

runme

One last trick and possibly the coolest, or at least IMHO, reflection permits to build a function call 100% dynamically, only by reflecting variables. Why would one do that? Well imagine a program calling functions using os.Args, without the need of a gigantic switch of many if.

Method building follows the same scheme as the Field method, meaning that you can find and build a name either by index Method() or by name MethodByName(). There’s one catch though, don’t forget reflect operates on variables, and we can’t search for a function from thin air, it has to be bound to some kind of variable; fortunately, Go gives the possibility to attach methods to variables. Here’s an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
"fmt"
"reflect"
)

type RetVal int

func (r *RetVal) Foo() {
fmt.Println("hello from Foo!")
*r = 3
}

func main() {
var r RetVal
funcname := "Foo"

va := []reflect.Value{}

f := reflect.ValueOf(&r).MethodByName(funcname)
if f.IsValid() {
f.Call(va)
}
fmt.Printf("r is %d", r)
}

runme

In order to “build” the function call, we’re created a custom type, RetVal, to which we attach a Foo() method.
As you can see, we declare a string variable holding "Foo". It is mandatory to declare the build function call parameters list, and as we could expect, those are reflect.Value types.
To be able to modify the value of r, we pass it by reference, but we perfectly could have passed it by value if we were not to assign 3 to it in the function.
Before calling a dynamic function, it is always a good idea to verify that it is actually valid using the IsValid method.
Finally, the created Value (f) can be Call()ed with optional parameters.

I found this method useful when writing a Mattermost bot which features can be called through a parameter passed in the chat.