Reflections In Go

Go is a static language with well reflection support. The remaining of this article will explain the reflection functionalities provided in the reflect standard package. Many reflection related details will also be listed.

It is very helpful to read the overview of Go type system and interfaces in Go articles before reading the remaining of the current article.

Overview Of Go Reflection

From the last article, we know that Go 1 lacks of generic support for custom types and functions. Go reflection brings many dynamic functionalities to Go programming, which makes up for the lacking of custom generic problem to some extent (though the reflection way is less efficient than real generic from the CPU consuming view). Many standard code packages, such as the fmt and encoding packages, rely on the reflection functionalities heavily.

We can inspect Go values through the values of the Type and Value types defined in the reflect standard package. The following two sections will show some examples on how to use values of the two types.

One of the Go reflection design goals is any non-reflection operation should be also possible to be applied through the reflection ways. For all kinds of reasons, this goal is not 100 percent achieved currently (Go 1.10). However, most non-reflection operations can be applied through the reflection ways now. On the other hand, through the reflection ways, we can do some operations which are impossible to be achieved through non-reflection ways. The operations which can't and can only be achieved through the reflection ways will be mentioned in the following sections.

The reflect.Type Type And Values

In Go, we can create a reflect.Type value from an arbitrary non-interface value by calling the reflect.TypeOf function. A reflect.TypeOf function call will convert its only argument passed to it to an interface{} value, then retrieve the information of the dynamic type from the interface{} value and store the type information in a reflect.Type return result. We can think the reflect.Type return result represents the type of the dynamic value of the interface{} value.

It is impossible to let a reflect.TypeOf function call return a reflect.Type value which represents an interface type. We have to use some indirect ways to get such a reflect.Type value. One of these indirect ways is shown in the second example below.

The reflect.Type type is an interface type. It specified several methods. We can call these methods to inspect the information of the type represented by a reflect.Type receiver value. Some of these methods apply for all kinds of types, some of them are kind-specific. Calling one kind-specific method for a type with wrong kind will panic. Please read the reflect standard package documentation for details.

An example:
package main

import "fmt"
import "reflect"

func main() {
	type A = [16]int16
	var c <-chan map[A][]byte
	tc := reflect.TypeOf(c)
	fmt.Println(tc.Kind())    // chan
	fmt.Println(tc.ChanDir()) // <-chan
	tm := tc.Elem()
	ta, tb := tm.Key(), tm.Elem()
	fmt.Println(tm.Kind(), ta.Kind(), tb.Kind()) // map array slice
	tx, ty := ta.Elem(), tb.Elem()

	// byte is an alias of uint8
	fmt.Println(tx.Kind(), ty.Kind()) // int16 uint8
	fmt.Println(tx.Bits(), ty.Bits()) // 16 8
	fmt.Println(tx.ConvertibleTo(ty)) // true
	fmt.Println(tb.ConvertibleTo(ta)) // false

	// Slice and map types are uncomparable.
	fmt.Println(tb.Comparable()) // false
	fmt.Println(tm.Comparable()) // false
	fmt.Println(ta.Comparable()) // true
	fmt.Println(tc.Comparable()) // true
}

In the above example, we use the method Elem to get the element types of some container types (a channel type, a map type, a slice type and an array type). In fact, we can also use this method to get the base type of a pointer type. For example,
package main

import "fmt"
import "reflect"

type T []interface{m()}
func (T) m() {}

func main() {
	tp := reflect.TypeOf(new(interface{}))
	tt := reflect.TypeOf(T{})
	fmt.Println(tp.Kind(), tt.Kind()) // ptr slice
	
	// Get two interface Types indirectly.
	ti, tim := tp.Elem(), tt.Elem()
	fmt.Println(ti.Kind(), tim.Kind()) // interface interface
	
	fmt.Println(tt.Implements(tim))  // true
	fmt.Println(tp.Implements(tim))  // false
	fmt.Println(tim.Implements(tim)) // false

	// All types implement any blank interface type.
	fmt.Println(tp.Implements(ti))  // true
	fmt.Println(tt.Implements(ti))  // true
	fmt.Println(tim.Implements(ti)) // true
	fmt.Println(ti.Implements(ti))  // true
}

We can get the field type and method information of a type through reflection. We can also get the parameter and result type information of a function type through reflection.
package main

import "fmt"
import "reflect"

type F func(string, int) bool
func (f F) Validate(s string) bool {
	return f(s, 32)
}

func main() {
	var x struct {
		n int
		f F
	}
	tx := reflect.TypeOf(x)
	fmt.Println(tx.Kind())     // struct
	fmt.Println(tx.NumField()) // 2
	tf := tx.Field(1).Type
	fmt.Println(tf.Kind())               // func
	fmt.Println(tf.IsVariadic())         // false
	fmt.Println(tf.NumIn(), tf.NumOut()) // 2 1
	fmt.Println(tf.NumMethod())          // 1
	ts, ti, tb := tf.In(0), tf.In(1), tf.Out(0)
	fmt.Println(ts.Kind(), ti.Kind(), tb.Kind()) // string int bool
}

Beside the TypeOf function, we can also use some other functions in the reflect standard package to create reflect.Type values which represent some composite types.
package main

import "fmt"
import "reflect"

func main() {
	ta := reflect.ArrayOf(5, reflect.TypeOf(123))
	fmt.Println(ta) // [5]int
	tc := reflect.ChanOf(reflect.SendDir, ta)
	fmt.Println(tc) // chan<- [5]int
	tp := reflect.PtrTo(ta)
	fmt.Println(tp) // *[5]int
	ts := reflect.SliceOf(tp)
	fmt.Println(ts) // []*[5]int
	tm := reflect.MapOf(ta, tc)
	fmt.Println(tm) // map[[5]int]chan<- [5]int
	tf := reflect.FuncOf(
		[]reflect.Type{ta},
		[]reflect.Type{tp, tc},
		false)
	fmt.Println(tf) // func([5]int) (*[5]int, chan<- [5]int)
	tt := reflect.StructOf([]reflect.StructField{
		{Name: "Age", Type: reflect.TypeOf("abc")},
	})
	fmt.Println(tt)            // struct { Age string }
	fmt.Println(tt.NumField()) // 1
}

There are more reflect.Type methods which are not used in above examples, please read the reflect package documentation for their usages.

Note, up to now (Go 1.10), there are no ways to create interface types through reflection. This is a known limitation of Go reflection.

Another limitation is, although we can create a struct type embedding other types as anonymous fields through reflection, the struct type may or may not obtain the methods of the embedded types, and creating a struct type with anonymous fields even might panic at run time. In other words, the behavior of creating struct types with anonymous fields is partially compiler dependent.

The third limitation is we can't declare new types through reflection.

The reflect.Value Type And Values

Similarly, we can create a reflect.Value value from an arbitrary non-interface value by calling the reflect.ValueOf function. A reflect.ValueOf function call will convert its only argument passed to it to an interface{} value, then retrieve the information of the dynamic value (and the dynamic type) from the interface{} value and store the information in a reflect.Value return result. We can think the reflect.Value return result represents the type of the dynamic value of the interface{} value.

It is impossible to let a reflect.ValueOf function call return a reflect.Value value which represents an interface value. We have to call some methods of other reflect.Value values to get reflect.Value values representing interface values.

There are plenty of methods declared for the reflect.Value type. We can call these methods to inspect the information of (and manipulate) the Go value represented by a reflect.Value receiver value. Some of these methods apply for all kinds of values, some of them are kind-specific. Calling one kind-specific method for a Go value with wrong kind will panic. Please read the reflect standard package documentation for details.

Each reflect.Value value has a CanSet method, which returns whether or not the Go value represented by that reflect.Value value is modifiable (assignable). If the Go value is modifiable, we can call the Set method of that reflect.Value value to modify the Go value. Note, the reflect.Value values returned directly by reflect.ValueOf function calls are always read-only.

An example:
package main

import "fmt"
import "reflect"

func main() {
	n := 123
	p := &n
	vp := reflect.ValueOf(p)
	fmt.Println(vp.CanSet(), vp.CanAddr()) // false false
	vn := vp.Elem() // get the value referenced by vp
	fmt.Println(vn.CanSet(), vn.CanAddr()) // true true
	vn.Set(reflect.ValueOf(789)) // <=> vn.SetInt(789)
	fmt.Println(n) // 789
}

Non-exported fields of struct values can't be modified through reflections.
package main

import "fmt"
import "reflect"

func main() {
	var s struct {
		X interface{} // an exported field
		y interface{} // a non-exported field
	}
	vp := reflect.ValueOf(&s)
	// If vp represents a pointer. the following
	// line is equivalent to "vs := vp.Elem()".
	vs := reflect.Indirect(vp)
	// vx and vy both represent interface values.
	vx, vy := vs.Field(0), vs.Field(1)
	fmt.Println(vx.CanSet(), vx.CanAddr()) // true true
	// vy is addressable but not modifiable.
	fmt.Println(vy.CanSet(), vy.CanAddr()) // false true
	vb := reflect.ValueOf(123)
	vx.Set(vb)     // okay, for vx is modifiable.
	// vy.Set(vb)  // will panic, for vy is not modifiable.
	fmt.Println(s) // {123 <nil>}
	fmt.Println(vx.IsNil(), vy.IsNil()) // false true
}

There are also some reflect.Value related functions declared in the reflect standard package. Each of these functions corresponds a built-in function or a non-reflection functionality, The following example demonstrates how to bind a custom generic function to different function values.
package main

import "fmt"
import "reflect"

func InvertSlice(args []reflect.Value) (result []reflect.Value) {
	inSlice, n := args[0], args[0].Len()
	outSlice := reflect.MakeSlice(inSlice.Type(), 0, n)
	for i := n-1; i >= 0; i-- {
		element := inSlice.Index(i)
		outSlice = reflect.Append(outSlice, element)
	}
	return []reflect.Value{outSlice}
}

func Bind(p interface{}, f func ([]reflect.Value) []reflect.Value) {
	// Get dynamic Values of interface Values by using the Elem method.
	invert := reflect.ValueOf(p).Elem()
	invert.Set(reflect.MakeFunc(invert.Type(), f))
}

func main() {
	var invertInts func([]int) []int
	Bind(&invertInts, InvertSlice)
	fmt.Println(invertInts([]int{2, 3, 5})) // [5 3 2]

	var invertStrs func([]string) []string
	Bind(&invertStrs, InvertSlice)
	fmt.Println(invertStrs([]string{"Go", "C"})) // [C Go]
}

Note, from the above several examples, we should learn that the Elem method of the reflect.Value type can not only be used to get the value referenced by a pointer value, it can also be used to get the dynamic value of an interface value.

If a reflect.Value represents a function (or method) value, then we can call the Call method of the reflect.Value to call the represented function (or method).
package main

import "fmt"
import "reflect"

type T struct {
	A, b int
}

func (t T) AddSubThenScale(n int) (int, int) {
	return n * (t.A + t.b), n * (t.A - t.b)
}

func main() {
	t := T{5, 2}
	vt := reflect.ValueOf(t)
	vm := vt.MethodByName("AddSubThenScale")
	results := vm.Call([]reflect.Value{reflect.ValueOf(3)})
	fmt.Println(results[0].Int(), results[1].Int()) // 21 9

	neg := func(x int) int {
		return -x
	}
	vf := reflect.ValueOf(neg)
	fmt.Println(vf.Call(results[:1])[0].Int()) // -21
	fmt.Println(vf.Call([]reflect.Value{
		vt.FieldByName("A"), // panic if the field name is "b"
	})[0].Int()) // -5
}

Please note that, reflect.Value values representing non-exported fields shouldn't be used as arguments of calls to reflection functions. If the line vt.FieldByName("A") in the above example is replaced with vt.FieldByName("b"), a panic will occur.

A reflection example for channel values.
package main

import "fmt"
import "reflect"

func main() {
	c := make(chan string, 2)
	vc := reflect.ValueOf(c)
	vc.Send(reflect.ValueOf("C"))
	succeeded := vc.TrySend(reflect.ValueOf("Go"))
	fmt.Println(succeeded) // true
	succeeded = vc.TrySend(reflect.ValueOf("C++"))
	fmt.Println(succeeded) // false
	fmt.Println(vc.Len(), vc.Cap()) // 2 2
	vs, succeeded := vc.TryRecv()
	fmt.Println(vs.String(), succeeded) // C true
	vs, sentBeforeClosed := vc.Recv()
	fmt.Println(vs.String(), sentBeforeClosed) // Go false
	vs, succeeded = vc.TryRecv()
	fmt.Println(vs.String(), succeeded) // <invalid Value> false
}

The TrySend and TryRecv methods correspond one-case-one-default select control flow code blocks.

We can use the reflect.Select function to simulate a select code block with dynamic number of case branches at run time.
package main

import "fmt"
import "reflect"

func main() {
	c := make(chan int, 1)
	vc := reflect.ValueOf(c)
	succeeded := vc.TrySend(reflect.ValueOf(123))
	fmt.Println(succeeded, vc.Len(), vc.Cap()) // true 1 1

	vSend, vZero := reflect.ValueOf(789), reflect.Value{}
	branches := []reflect.SelectCase{
		{Dir: reflect.SelectDefault, Chan: vZero, Send: vZero},
		{Dir: reflect.SelectRecv, Chan: vc, Send: vZero},
		{Dir: reflect.SelectSend, Chan: vc, Send: vSend},
	}
	selIndex, vRecv, sentBeforeClosed := reflect.Select(branches)
	fmt.Println(selIndex)         // 1
	fmt.Println(sentBeforeClosed) // true
	fmt.Println(vRecv.Int())      // 123
	vc.Close()
	// Remove the send case branch this time, for it may cause panic.
	selIndex, _, sentBeforeClosed = reflect.Select(branches[:2])
	fmt.Println(selIndex, sentBeforeClosed) // 1 false
}

There are more reflect.Value related functions and methods which are not used in above examples, please read the reflect package documentation for their usages.

More Reflection Related Details

The Results Of reflect.DeepEqual(x, y) And x == y May Be Different

The function call reflect.DeepEqual(x, y) will always return false if the types of its two arguments are different, whereas x == y may return true even if the types of the two operands are different.

The second difference is a DeepEqual call with two pointer argument values of the same type returns whether or not the two respective values referenced by the two pointers are deep equal. So the call might return true even if the two pointers are not equal.

The third difference is the result of a DeepEqual call may be not correct if the compared two arguments are in the same cyclic reference chain.

The fourth difference is, the function call reflect.DeepEqual(x, y) is not expected to panic generally, whereas x == y will panic if the two operands are both interface values and their dynamic types are identical and uncomprable.

Note, a DeepEqual call with two function argument values returns true only if the two functions are both nil and their types are identical.

An example showing these differences:
package main

import "fmt"
import "reflect"

func main() {
	type Book struct {page int}
	x := struct {page int}{123}
	y := Book{123}
	fmt.Println(reflect.DeepEqual(x, y)) // false
	fmt.Println(x == y)                  // true

	z := Book{123}
	fmt.Println(reflect.DeepEqual(&z, &y)) // true
	fmt.Println(&z == &y)                  // false

	type T struct{p *T}
	t := &T{&T{nil}}
	t.p.p = t // form a cyclic reference chain.
	fmt.Println(reflect.DeepEqual(t, t.p)) // true
	fmt.Println(t == t.p)                  // false
	
	var f1, f2 func() = nil, func(){}
	fmt.Println(reflect.DeepEqual(f1, f1)) // true
	fmt.Println(reflect.DeepEqual(f2, f2)) // false

	var a, b interface{} = []int{1, 2}, []int{1, 2}
	fmt.Println(reflect.DeepEqual(a, b)) // true
	fmt.Println(a == b)                  // panic
}

A []MyByte Value Can Be Converted To A []byte Value Through Reflection

Assume the underlying type of a defined type MyByte is the predeclared type byte, we know that Go type system forbids the conversions between []MyByte and []byte values. However, it looks the implementation of the method Bytes of the reflect.Value type partially violates this restriction unintentionally, by allowing converting a []MyByte value to []byte.

Example:
package main

import "bytes"
import "fmt"
import "reflect"

type MyByte byte

func main() {
	var mybs = []MyByte{'a', 'b', 'c'}
	var bs []byte

	// bs = []byte(mybs) // this line fails to compile

	v := reflect.ValueOf(mybs)
	bs = v.Bytes() // okay. Violating Go type system.
	fmt.Println(bytes.HasPrefix(bs, []byte{'a', 'b'})) // true

	bs[1], bs[2] = 'r', 't'
	fmt.Printf("%s \n", mybs) // art
}

I think the voilation is not harmful. On the contrary, it makes some benefits. For example, with this voilation, we can use the functions in the bytes standard package for the []MyByte values.

The Go 101 project is hosted on both github and gitlab. Welcome to improve Go 101 articles by submitting corrections for all kinds of mistakes, such as typos, grammar errors, wording inaccuracies, description flaws and code bugs.