Sab's

Golang Reflect

Reflection in Golang

Incase you are here looking to learn about reflection, a better resource is
https://blog.golang.org/laws-of-reflection

Interfaces in Go are types which hold concrete value and underlying type of the value with a precondition that value should implement methods of the interface. For example; types implementing Read([]byte) (int, error) method satisfy the io.Reader interface. However interface{}, without any method definition will match all types.

A struct type can be assigned to an empty interface, the assertion is the concrete type should implement the methods of the interface type. In the following example there are no methods that need to be implemented, hence the assertion passes.

type T struct {
    x string
}

t := T{}
var x interface{}
x = t
example 1

On inspecting the interface, reflect.Type represents the value part of the interface and reflect.Type represents the underlying type of the value in the interface. The actual interface can be got with the Interface() method of the Value.

type T struct {
  x string
}

x := T{"hello"}
p := reflect.ValueOf(x)
fmt.Println(p.Interface())
fmt.Println("type of p:", p.Type())
fmt.Println(p.Kind())
fmt.Println(p.CanSet())
&{hello}
type of p: *main.T
ptr
false
example 2

Can the value be updated

Most often we need to modify value of a struct. CanSet() is used to know if the interface values can be updated. From example 1, the value is not settable. That is because we should be looking at the value p is pointing which can be found by using Elem() method.

p.Elem().CanSet()

This still would not work because the value is not a refrence to x but rather copy of x.

type T struct {
  x string
}

x := T{"hello"}
p := reflect.ValueOf(&x)
fmt.Println(p.Interface())
fmt.Println("type of p:", p.Type())
fmt.Println(p.Elem().CanSet())
&{hello}
type of p: *main.T
true
example 3

Accessing struct fields

struct fields can be accessed using the Field, FieldByName, FieldbyNameFunc methods.

type T struct {
  X string
  Y string
}

x := T{}
p := reflect.ValueOf(&x)
p.Elem().Field(0).SetString("Hello")
p.Elem().FieldByName("Y").SetString("you")
fmt.Println(x)
{Hello you}
example 4

Struct tags

StructTag is the approach many libraries take for accessing and modifying struct values. Which many of us are familiar with Go's json module.

type T struct {
   X string `json:"x_struct_tag"`
}
fmt.Println(reflect.TypeOf(&T{}).Elem().NumField())
fmt.Println(reflect.TypeOf(&T{}).Elem().Field(0).Tag.Get("json"))
1
x_struct_tag