golang

Golang Reflect

Welcome to another Golang tutorial. We will learn about reflection in the Go programming language in this one.

What is Reflection?

Reflection refers to the method of analyzing and inspecting variables and their values during runtime. It is a very useful technique when dealing with abstract components of a structure. This does not mean that it is limited to structures.

Let us discuss various components of reflection in Golang. Enjoy!

Required Imports

In Go, the ability to perform reflection is provided using the reflect package. Hence, we need to import it before use.

You can import it as shown in the snippet below:

import "reflect"

Once imported, you can start using the provided methods and functionalities.

TypeOf()

One method from the reflect package is the TypeOf(). This function allows you to determine the type of a variable.

To use it, we can do:

package main
import (
        "fmt"
        "reflect"
)
func main() {
        var1 := 100
        var2 := 3.14159
        var3 := "hello"
        var4 := [...]int{1, 2, 3}
        var5 := map[string]string{}
        var6 := true
        var7 := []int{1, 2, 4}

        fmt.Println("Type => ", reflect.TypeOf(var1))
        fmt.Println("Type => ", reflect.TypeOf(var2))
        fmt.Println("Type => ", reflect.TypeOf(var3))
        fmt.Println("Type => ", reflect.TypeOf(var4))
        fmt.Println("Type => ", reflect.TypeOf(var5))
        fmt.Println("Type => ", reflect.TypeOf(var6))
        fmt.Println("Type => ", reflect.TypeOf(var7))
}

The above example uses reflect.TypeOf() method to check the data types of various variables. The resulting output is as shown:

Type =int
Type =float64
Type =string
Type =[3]int
Type =map[string]string
Type =bool
Type =[]int

ValueOf()

The reflect.ValueOf() method returns the value of a specific variable. An example is as shown:

fmt.Println("Value => ", reflect.ValueOf(var4))

This should return the value of the var4 variable.

Output:

Value =[1 2 3]

Copy()

The copy method is used to copy the elements of a specific source to a specified destination. The function will perform the copy operation until the destination is full of the elements from the source are exhausted.

The function returns the number of elements copied from the source to the destination.

Remember that the destination and source must be of the same type.

Consider the example shown below:

package main
import (
        "fmt"
        "reflect"
)
func main() {
        src := reflect.ValueOf([]string{"a", "b", "c"})
        dest := reflect.ValueOf([]string{"d", "e", "f"})
        items_copied := reflect.Copy(src, dest)
        fmt.Println("Elements copied: ", items_copied)
        fmt.Println("Source: ", src)
        fmt.Println("Destination: ", dest)
}

In the example above, we use the reflect.ValueOf() to cast the variable to its type. We then use the Copy() method to copy the elements of the dest to the src variable. The resulting output is as shown:

Elements copied:  3
Source:  [d e f]
Destination:  [d e f]

Swapper()

The swapper() method allows you to swap elements in a slice. An example is as shown below:

lst := []int{1, 2, 3, 4, 5}
lst_swp := reflect.Swapper(lst)
fmt.Printf("Before Swap: %v\n", lst)
lst_swp(0, 4)
fmt.Printf("After Swap: %v\n", lst)

The example above swaps the slice from the first index to the last. The output is as shown:

Before Swap: [1 2 3 4 5]
After Swap: [5 2 3 4 1]

NumField()

The NumField() method returns the number of fields within a given structure. An example is as shown:

type my_struct struct {
        field_1 string
        field_2 int
        field_3 float64
        field_4 bool
}
struct_1 := my_struct{"a", 1, 3.14, false}
cast := reflect.TypeOf(struct_1)
fmt.Println(cast.NumField())

The above should return the number of fields in the structure.

Output:
4

Field()

The field() method returns the name and the data type of fields within a structure.

struct_1 := my_struct{"a", 1, 3.14, false}
cast := reflect.TypeOf(struct_1)
for i := 0; i < cast.NumField(); i++ {
        field := cast.Field(i)
        fmt.Println(field.Name, field.Type)
}

The above program returns the name of the fields in the struct and their data types.

Output:
field_1 string
field_2 int
field_3 float64
field_4 bool

MakeChan()

The MakeChan() method creates a specified type channel and buffers size channel. Example:

var str chan string
var str_Type reflect.Value = reflect.ValueOf(&str)
new_Channel := reflect.MakeChan(reflect.Indirect(str_Type).Type(), 256)
fmt.Println("Channel Kind: ", new_Channel.Kind())
fmt.Println("Channel Cap: ", new_Channel.Cap())
}

The above should create a channel of chan type and a buffer size of 256. The resulting output is as shown:

Channel Kind:  chan
Channel Cap:  256

MakeMap()

As the name suggests, the MakeMap() function creates a map of the defined data type.

Take the example below:

var str map[string]string
var str_type reflect.Value = reflect.ValueOf(&str)
my_map := reflect.MakeMap(reflect.Indirect(str_type).Type())
fmt.Println("Kind => ", my_map.Kind())

This creates a new map.

Conclusion

In this guide, we scratched the surface of using the reflect package in Go. Keep in mind that the package offers much more than what is discussed here.

Keep practicing!

About the author

John Otieno

My name is John and am a fellow geek like you. I am passionate about all things computers from Hardware, Operating systems to Programming. My dream is to share my knowledge with the world and help out fellow geeks. Follow my content by subscribing to LinuxHint mailing list