GOLang: Reflection
Must Read
- https://blog.golang.org/laws-of-reflection
- https://golang.org/pkg/reflect/
- https://golang.org/pkg/reflect/#Kind
- https://golang.org/pkg/reflect/#Value
Reflection is a way to examine own structure. Let’s try and learn it via examples.
func main() {
//exampleOne()
i := 0
fmt.Println(reflect.TypeOf(i))
fmt.Println(reflect.ValueOf(i))
}
Here I have defined a variable i := 0
and inspecting it using reflection.
int
0
i := 0
fmt.Println(" Reflection: Int")
fmt.Println(reflect.TypeOf(i))
fmt.Println(reflect.ValueOf(i))
str := "Abc"
fmt.Println(reflect.TypeOf(str))
fmt.Println(reflect.ValueOf(str))
The same way it works on other type
int
0
string
Abc
How about using a custom type instead of int
type MyInt int
var myInt MyInt
myInt = 0
fmt.Println(reflect.TypeOf(myInt))
fmt.Println(reflect.ValueOf(myInt))
main.MyInt
0
Variable i
and myInt
have distinct static types. Underlying types are same for both of them, but we cannot assign them to each other without conversion.
myInt = i
Any statement like that will lead to a compile time error.
cannot use
i (type int)
as typeMyInt
in assignment
i = 10
myInt = MyInt(i)
fmt.Println(reflect.TypeOf(myInt))
fmt.Println(reflect.ValueOf(myInt))
main.MyInt
10
Let’s define a custom type with more content and read about using the StructField
// MyStructTags Reflect pacakge to learn more about a field.
type MyStructTags struct {
Fi int64 `json:"intField" defines:"age"`
Fb bool `json:"boolField" defines:"state"`
Ff float64 `json:"floatField" defines:"currency"`
Fs string `json:"stringField" defines:"name"`
}
// ReadTags Reads the tag
func ReadTags(tt MyStructTags, ix int) {
ttType := reflect.TypeOf(tt)
ixField := ttType.Field(ix) // getting field at a position ix
fmt.Printf("%v:%s:%v:%v\n", ixField.Tag, ixField.Name, ixField.Offset, ixField.Type) // printing tags
}
myRef := ref.MyStructTags{1, false, 1.52, "What is my name?"}
for i = 0; i < 4; i++ {
ref.ReadTags(myRef, i)
}
The output is as under
json:"intField" defines:"age":Fi:0:int64
json:"boolField" defines:"state":Fb:8:bool
json:"floatField" defines:"currency":Ff:16:float64
json:"stringField" defines:"name":Fs:24:string
Looking at the documentation for the SructField
type StructField struct {
// Name is the field name.
Name string
// PkgPath is the package path that qualifies a lower case (unexported)
// field name. It is empty for upper case (exported) field names.
// See https://golang.org/ref/spec#Uniqueness_of_identifiers
PkgPath string
Type Type // field type
Tag StructTag // field tag string
Offset uintptr // offset within struct, in bytes
Index []int // index sequence for Type.FieldByIndex
Anonymous bool // is an embedded field
}
Setting Values
How about setting the value of the field?
type MyInt int
var myInt MyInt
reflect.ValueOf(myInt).SetInt(22)
if reflect.ValueOf(myInt).CanSet() {
reflect.ValueOf(myInt).SetInt(22)
}else {
fmt.Println(" CanSet returned false")
}
We will use Elem
to set the value
fmt.Println(reflect.ValueOf(&myInt).Kind())
fmt.Println(reflect.ValueOf(&myInt).Elem().CanSet())
reflect.ValueOf(&myInt).Elem().SetInt(24)
fmt.Println(reflect.ValueOf(myInt).Interface())
ptr
true
24