Reflect in Golang

Learn via video courses
Topics Covered

:::

Overview

Reflection is an advanced topic in Golang. It is a concept that comes from the metaprogramming paradigm. This lesson will teach you about Go's reflection in a detail.

What is Reflection?

Reflect in Golang is a tool to analyze its variables and values and also find their types at runtime, along with creating and modifying them. With reflection, a program can inspect the type, value, and internal structure of a variable at runtime. This can be useful for situations where the type of a variable is not known at compile time, such as when working with interfaces or when creating generic functions.

Reflection in Go is built around three concepts: Types, Kinds, and Values to find out information.

What is the Need to Inspect a Variable and Find Its Type?

Inspecting a variable and finding its type can be useful in several scenarios. Some examples include:

  • Type checking: Go is a strongly typed language, which means that the type of a variable must be specified and cannot change. By inspecting a variable's type, we can ensure that we are using it in the correct way and avoid type errors.
  • Type-specific functionality: Different types have different functionality and methods associated with them. By inspecting a variable's type, we can determine which methods and functionality are available.
  • Type casting: In some cases, we may need to convert a variable of one type to another. By inspecting a variable's type, we can determine if it can be safely cast to a different type.

The output of the above code:

https://go.dev/play/p/uQeIqWD5q3E

Explanation of the code

In this example, we are using the reflect.TypeOf function to get the type of each variable in which myNum is of int type myString is of string type and myBool is of bool type. -->

Reflect Packages with Implementation and Examples

Type Function

reflect.Type() function is used to return the type of reflect. In simpler words, it is used to know the data type of a variable.

For Example:

Output:

https://go.dev/play/p/vhvEhlANXnD

Explanation of the code

  • In this code, we are using the reflect.TypeOf function to get the type of different variables. The reflect.TypeOf function takes an interface{} as an argument and returns a reflect.Type type, which represents a type of any value.
  • In the first line, we are declaring a variable name of the type string and assign it the value "Scaler". We then use reflect.TypeOf(name) to get the type of the name variable, and print it using fmt.Println.
  • Next, we are declaring a variable v of type []int and assign it an array of integers. We then use reflect.TypeOf(v) to get the type of the v variable, and print it using fmt.Println.
  • Finally, we are declaring a variable num of type int and assign it the value 123. We then use reflect.TypeOf(num) to get the type of the num variable, and print it using fmt.Println.

Value Function

reflect.Value() function creates reflect. Value instance that is used to represent the value of the variable. In simple words, it is used to find the value of the variable.

For Example:

Output:

https://go.dev/play/p/LK5xkUT3uEH

Explanation of the code

  • In this code, we are using the reflect.ValueOf function to get the value of different variables. The reflect.ValueOf function takes an interface{} as an argument and returns a reflect.Value type, which represents a value of any type.
  • In the first line, we are declaring a variable name of the type string and assign it the value "Scaler". We then use reflect.ValueOf(name) to get the value of the name variable, and print it using fmt.Println.
  • In the second line, we are declaring a variable v of type []int and assign it an array of integers. We then use reflect.ValueOf(v) to get the value of the v variable, and print it using fmt.Println.
  • Next, we are declaring a variable num of type int and assign it the value 123. We then use reflect.ValueOf(num) to get the value of the num variable, and print it using fmt.Println.

Kind Function

The Kind() function in Go's reflect package is used to determine the kind of a variable. It returns a constant value of the reflect.Kind type, which is an enumeration of the different possible kinds of variables in Go.

For Example:

Output for the above code:

https://go.dev/play/p/qd5FlqDV2sl

Explanation of the code

In the above example, we have x which is of int type, and using a kind that prints int as an output.

NumField and Field Function

The NumField() function returns the number of fields in a struct. It takes a reflect.Type value as its argument, which can be obtained by calling the reflect.TypeOf() function on a struct value.

Field() function is used to return the reflect.Value of the ith field(using indexing variable). The function takes two arguments: first, the reflect.Type value of the struct, and second the index of the field.

NumField()

Example:

Output for the above code:

https://go.dev/play/p/AUu_OF1rjkr

Explanation of the code

  • In this example, we have defined a struct User with three fields Name, Age, and Address. By calling the NumField() function on the struct, it returns the number of fields present in the struct which is 3.
  • It's important to note that the NumField() function only returns the number of fields that are defined in the struct itself and not the embedded fields. If you have an embedded struct and want to know the total number of fields you can use the NumField() function on the embedded struct along with the struct that embeds it.
  • Also, the NumField() function can only be used on structs, if you pass any other type of variable it will panic.

Here is an example of how to use the Field() function::

The output of the above code:

https://go.dev/play/p/juP7uwzNFLQ

Explanation of the code

  • In this example, we have defined a struct User with three fields Name, Age, and Address. By calling the Field(1) function on the struct t, it returns the second field of the struct which is "Age" with type int.
  • Also, the Field() function can only be used on structs, if you pass any other type of variable it will panic.

Copy Function

The Copy() function in the reflect package in Go is used to make a copy of the value of a variable. It takes two arguments, the first is the value to be copied, and the second is the value to which the copy will be made. Both the destination and the source must have Slice or Array, and also they should contain the same element type.

Here is an example of how to use the Copy() function:

Output for the above code:

https://go.dev/play/p/cBTmbCNXiKc

Explanation of the code

  • In the above code, we are copying the values of the slice y to x using the reflect.Copy function. After the copy, the values in x become [4,5,6]
  • It's important to note that the Copy() function can only be used to copy between variables of the same type and if they are both addressable and settable, otherwise it will panic. Also, the Copy() function only copy the top level of the value if it's a struct, it doesn't copy nested fields.

DeepEqual Function

reflect.DeepEqual() function returns either True or False which means it only deals with bool values in Golang. DeepEqual means whether they are "deeply equal" or not.

For Example:

Output for the above code:

Run the Code!

Explanation of the code

  • In this example, we are comparing the equality of the two slices x and y using the reflect.DeepEqual function. It returns true as the slices have the same elements in the same order.
  • It's important to note that the DeepEqual() function can be used to compare any two Go values and it will recursively compare the values of structs, maps, slices, and arrays.

Swapper Function

The Swapper function in the reflect package in Go is a function that can be used to swap the values of two variables. The function takes two arguments, which must be pointers to the variables that you want to swap.

For Example:

Output for the above code:

Run the code!

Explanation of the code

  • In the above code reflect package is used to swap elements in a slice. The main function first defines a slice src with the values 1, 2, 3, 4, 5.
  • It then prints the slice before the swap. The reflect.The swapper function is used to create a function swapF that can be used to swap elements in the src slice. The swapF function is then called with the arguments 1 and 4, which swap the elements at index 1 and index 4 in the src slice.
  • Finally, the program prints the src slice after the swap to show that the elements at index 1 and 4 have been swapped.

FieldByIndex Function

The reflect.FieldByIndex() method is used to retrieve the nested field associated with that index.

For Example:

Output for the above code:

Run the code!

Explanation of the code

  • This code defines a struct type called MyStruct, which has two fields, Field1 of type string and Field2 of type int.
  • In the main function, an instance of MyStruct is created, and its fields are initialised with the values "hello" and 42 respectively.
  • The reflect.ValueOf(s) function is used to get a reflect.Value representing the struct.
  • The first use of the FieldByIndex function is passing a single element slice []int{0} to it as an argument that represents the index of the field within the struct. The second use of the FieldByIndex function is passing a single element slice []int{1} to it as an argument that represents the index of the field within the struct. In this case, the second field "Field2" is an int type. The Int() method is used to convert the value of the field to an int and it's printed on the console.

FieldByName Function

The FieldByName function in the reflect package in Go (also known as Golang) is used to retrieve the value of a struct field given its name. The function takes a single argument, which is a string representing the name of the field to retrieve.

Here is an example of how to use the FieldByName function:

Output for the above code:

Run the code!

Explanation of the code

In this example, the FieldByName function is used to retrieve the values of the Field1 fields of the MyStruct struct.

Int and String Functions

This method is used in the extraction of reflect.Value as int64 and string.

For example:

Output for the above code:

Run the Code!

Explanation of the code

In this example, the Int() function is used to convert the value of the variable x to an int.

The String() function is used to convert the value of a reflect.Value to a string type. It returns the value as a string and an error if the value is not a string type. Here is an example of how to use the String() function:

Output for the above code:

Run the code!

Explanation of the code:

In this example, the String() function is used to convert the value of the variable x to a string.

When to Use and Not Use Reflection

Here are some situations when you might want to use reflection:

  • When you need to work with unknown types: If you have a function that needs to work with a variable of an unknown type, reflection can be used to determine the type of the variable and call the appropriate methods or functions.
  • When you need to implement generic functionality: Reflection can be used to implement generic functionality that works with a wide range of types.

However, here are some situations when you might want to avoid using reflection:

  • When performance is critical: Reflect in Golang can be slow and can add overhead to your code, so it's best to avoid it in performance-critical sections of your code.
  • When code readability is important: Reflect in Golang can make code more difficult to understand, so it's best to avoid it in situations where code readability is important.
  • When you are working with a known type: If you know the type of a variable at compile-time, it's best to use the type's methods and functions directly instead of using reflection.

Conclusion

  • In this article we learned Reflect in Golang: which is powerful, but it should be used with caution as it can make code more complex and less efficient.
  • Next, different functions like the NumField() function in the reflect package in Go is used to determine the number of fields in a struct and it takes a reflect.Type value as its argument.
  • The Field(i) function in the reflect package in Go is used to access the i-th field of a struct and it takes two arguments: first, the reflect.Type value of the struct and the second is the index of the field. It returns a reflect.StructField type which contains information about the field such as its name, type, and tag.
  • the Copy() function in the reflect package in Go is used to make a copy of the value of a variable, it takes two arguments, the first is the value to be copied, and the second is the value to which the copy will be made.
  • The DeepEqual() function in the reflect package in Go is used to compare the equality of two variables by recursively comparing their values, it takes two arguments, the first is the first value to be compared, and the second is the second value to be compared. It returns a boolean value indicating whether the two values are equal and other functions also.