Reflection in Golang


Reflection

Reflection in Go is a form of metaprogramming. Reflection allows us to examine types at runtime. It also provides the ability to examine, modify, and create variables, functions, and structs at runtime. The Go reflect package gives you features to inspect and manipulate an object at runtime. Reflection is an extremely powerful tool for developers and extends the horizon of any programming language. Types, Kinds and Values are three important pieces of reflection that are used in order to find out information.


reflect.Copy() Function of Reflect Package

Copy copies the contents of source into destination until either destination has been filled or source has been exhausted. It returns the number of elements copied. Destination and source each must have kind Slice or Array, and destination and source must have the same element type.

Example

package main

import (
	"fmt"
	"reflect"
)

func main() {
	destination := reflect.ValueOf([]string{"A", "B", "C"})
	source := reflect.ValueOf([]string{"D", "E", "F"})

	// Copy() function is used and it returns the number of elements copied
	counter := reflect.Copy(destination, source)
	fmt.Println(counter)

	fmt.Println(source)
	fmt.Println(destination)
}

Output

3
[D E F]
[D E F]

reflect.DeepEqual() Function of Reflect Package

DeepEqual returns True or False whether x and y are "deeply equal" or not. Array values are deeply equal when their corresponding elements are deeply equal. Struct values are deeply equal if their corresponding fields, both exported and un-exported, are deeply equal. Slice values are deeply equal when (they are both nil or both non-nil, they have the same length, and either they point to the same initial entry of the same underlying array).

Example

package main

import (
	"fmt"
	"reflect"
)

type mobile struct {
	price float64
	color string
}

func main() {
	// DeepEqual is used to check two slices are equal or not
	s1 := []string{"A", "B", "C", "D", "E"}
	s2 := []string{"D", "E", "F"}
	result := reflect.DeepEqual(s1, s2)
	fmt.Println(result)

	// DeepEqual is used to check two arrays are equal or not
	n1 := [5]int{1, 2, 3, 4, 5}
	n2 := [5]int{1, 2, 3, 4, 5}
	result = reflect.DeepEqual(n1, n2)
	fmt.Println(result)

	// DeepEqual is used to check two structures are equal or not
	m1 := mobile{500.50, "red"}
	m2 := mobile{400.50, "black"}
	result = reflect.DeepEqual(m1, m2)
	fmt.Println(result)
}

Output

false
true 
false

reflect.Swapper() Function of Reflect Package

Swapper function is used to swaps the elements in the provided slice. You can use this function in trick way to reverse or sort the slice also.

Example

package main

import (
	"fmt"
	"reflect"
)

func main() {
	theList := []int{1, 2, 3, 4, 5}
	swap := reflect.Swapper(theList)
	fmt.Printf("Original Slice :%v\n", theList)

	// Swapper() function is used to swaps the elements of slice
	swap(1, 3)
	fmt.Printf("After Swap :%v\n", theList)

	// Reversing a slice using Swapper() function
	for i := 0; i < len(theList)/2; i++ {
		swap(i, len(theList)-1-i)
	}
	fmt.Printf("After Reverse :%v\n", theList)
}

Output

Original Slice :[1 2 3 4 5]
After  Swap :[1 4 3 2 5]
After Reverse :[5 2 3 4 1]

reflect.TypeOf() Function of Reflect Package

The reflect.TypeOf function returns a value of type reflect.Type, which represents the type of the variable passed into the TypeOf function.

Example

package main

import (
	"fmt"
	"reflect"
)

func main() {
	v1 := []int{1, 2, 3, 4, 5}
	fmt.Println(reflect.TypeOf(v1))

	v2 := "Hello World"
	fmt.Println(reflect.TypeOf(v2))

	v3 := 1000
	fmt.Println(reflect.TypeOf(v3))

	v4 := map[string]int{"mobile": 10, "laptop": 5}
	fmt.Println(reflect.TypeOf(v4))

	v5 := [5]int{1, 2, 3, 4, 5}
	fmt.Println(reflect.TypeOf(v5))

	v6 := true
	fmt.Println(reflect.TypeOf(v6))
}

Output

[]int
string        
int
map[string]int
[5]int        
bool

reflect.ValueOf() Function of Reflect Package

The reflect.ValueOf function to create a reflect.Value instance that represents the value of a variable. reflect.Value has methods for finding out information about the value of a variable.

Example

package main

import (
	"fmt"
	"reflect"
)

func main() {
	v1 := []int{1, 2, 3, 4, 5}
	fmt.Println(reflect.ValueOf(v1))

	v2 := "Hello World"
	fmt.Println(reflect.ValueOf(v2))

	v3 := 1000
	fmt.Println(reflect.ValueOf(v3))
	fmt.Println(reflect.ValueOf(&v3))

	v4 := map[string]int{"mobile": 10, "laptop": 5}
	fmt.Println(reflect.ValueOf(v4))

	v5 := [5]int{1, 2, 3, 4, 5}
	fmt.Println(reflect.ValueOf(v5))

	v6 := true
	fmt.Println(reflect.ValueOf(v6))
}

Output

[1 2 3 4 5]
Hello World
1000
0xc0000a00b8
map[laptop:5 mobile:10]
[1 2 3 4 5]
true

reflect.NumField() Function of Reflect Package

The reflect.NumField() Function returns the number of fields in the given struct

Example

package main

import (
	"fmt"
	"reflect"
)

type T struct {
	A int
	B string
	C float64
	D bool
}

func main() {
	t := T{10, "ABCD", 15.20, true}
	typeT := reflect.TypeOf(t)
	fmt.Println(typeT.NumField())
}

Output

4

reflect.Field() Function of Reflect Package

The reflect.Field() Function is used to access the name and type of struct fields.

Example

package main

import (
	"fmt"
	"reflect"
)

type T struct {
	A int
	B string
	C float64
	D bool
}

func main() {
	t := T{10, "ABCD", 15.20, true}
	typeT := reflect.TypeOf(t)

	for i := 0; i < typeT.NumField(); i++ {
		field := typeT.Field(i)
		fmt.Println(field.Name, field.Type)
	}
}

Output

A int
B string 
C float64
D bool

reflect.FieldByIndex() Function of Reflect Package

The reflect.FieldByIndex() Function is used to get the nested field corresponding to index.

Example

package main

import (
	"fmt"
	"reflect"
)

type First struct {
	A int
	B string
	C float64
}

type Second struct {
	First
	D bool
}

func main() {
	s := Second{First: First{10, "ABCD", 15.20}, D: true}
	t := reflect.TypeOf(s)

	fmt.Printf("%#v\n", t.FieldByIndex([]int{0}))
	fmt.Printf("%#v\n", t.FieldByIndex([]int{0, 0}))
	fmt.Printf("%#v\n", t.FieldByIndex([]int{0, 1}))
	fmt.Printf("%#v\n", t.FieldByIndex([]int{0, 2}))
	fmt.Printf("%#v\n", t.FieldByIndex([]int{1}))
}

Output

reflect.StructField{Name:"First", PkgPath:"", Type:(*reflect.rtype)(0x4bda40), Tag:"", Offset:0x0, Index:[]int{0}, Anonymous:true}
reflect.StructField{Name:"A", PkgPath:"", Type:(*reflect.rtype)(0x4ad800), Tag:"", Offset:0x0, Index:[]int{0}, Anonymous:false} 
reflect.StructField{Name:"B", PkgPath:"", Type:(*reflect.rtype)(0x4adf80), Tag:"", Offset:0x8, Index:[]int{1}, Anonymous:false} 
reflect.StructField{Name:"C", PkgPath:"", Type:(*reflect.rtype)(0x4ad400), Tag:"", Offset:0x18, Index:[]int{2}, Anonymous:false}
reflect.StructField{Name:"D", PkgPath:"", Type:(*reflect.rtype)(0x4ad200), Tag:"", Offset:0x20, Index:[]int{1}, Anonymous:false

reflect.FieldByName() Function of Reflect Package

The reflect.FieldByName() Function in Golang is used to get ands set the struct field value by given field name.

Example

package main

import (
	"fmt"
	"reflect"
)

type T struct {
	A int
	B string
	C float64
}

func main() {
	s := T{10, "ABCD", 15.20}
	fmt.Println(reflect.ValueOf(&s).Elem().FieldByName("A"))
	fmt.Println(reflect.ValueOf(&s).Elem().FieldByName("B"))
	fmt.Println(reflect.ValueOf(&s).Elem().FieldByName("C"))

	reflect.ValueOf(&s).Elem().FieldByName("A").SetInt(50)
	reflect.ValueOf(&s).Elem().FieldByName("B").SetString("Test")
	reflect.ValueOf(&s).Elem().FieldByName("C").SetFloat(5.5)

	fmt.Println(reflect.ValueOf(&s).Elem().FieldByName("A"))
	fmt.Println(reflect.ValueOf(&s).Elem().FieldByName("B"))
	fmt.Println(reflect.ValueOf(&s).Elem().FieldByName("C"))
}

Output

10
ABCD
15.2
50  
Test
5.5 

reflect.MakeSlice() Function of Reflect Package

MakeSlice creates a new zero-initialized slice value for the specified slice type, length, and capacity.

Example

package main

import (
	"fmt"
	"reflect"
)

func main() {
	var str []string
	var strType reflect.Value = reflect.ValueOf(&str)
	newSlice := reflect.MakeSlice(reflect.Indirect(strType).Type(), 10, 15)

	fmt.Println("Kind :", newSlice.Kind())
	fmt.Println("Length :", newSlice.Len())
	fmt.Println("Capacity :", newSlice.Cap())
}

Output

Kind : slice
Length : 10
Capacity : 15

reflect.MakeMap() Function of Reflect Package

MakeMap creates a new map with the specified type.

Example

package main

import (
	"fmt"
	"reflect"
)

func main() {
	var str map[string]string
	var strType reflect.Value = reflect.ValueOf(&str)
	newMap := reflect.MakeMap(reflect.Indirect(strType).Type())

	fmt.Println("Kind :", newMap.Kind())
}

Output

Kind : map

reflect.MakeChan() Function of Reflect Package

MakeChan creates a new channel with the specified type and buffer size.

Example

package main

import (
	"fmt"
	"reflect"
)

func main() {
	var str chan string
	var strType reflect.Value = reflect.ValueOf(&str)
	newChannel := reflect.MakeChan(reflect.Indirect(strType).Type(), 512)

	fmt.Println("Kind :", newChannel.Kind())
	fmt.Println("Capacity :", newChannel.Cap())
}

Output

Kind : chan
Capacity : 512

reflect.MakeFunc() Function of Reflect Package

The reflect.MakeFunc() Function is used to get the new function of the given Type that wraps the function fn.

Example

package main

import (
	"fmt"
	"reflect"
)

type Sum func(int64, int64) int64

func main() {
	t := reflect.TypeOf(Sum(nil))
	mul := reflect.MakeFunc(t, func(args []reflect.Value) []reflect.Value {
		a := args[0].Int()
		b := args[1].Int()
		return []reflect.Value{reflect.ValueOf(a + b)}
	})
	fn, ok := mul.Interface().(Sum)
	if !ok {
		return
	}
	fmt.Println(fn(5, 6))
}

Output

11