The Go programming language is widely known for its expressiveness. It is a strongly typed language but still gives applications the ability to dynamically manipulate and inspect objects including variables, functions, and types at runtime.

Reflection is the mechanism Go employs to accomplish this ability. What then, is reflection, and how can you apply reflection in your Go applications?

What Is Reflection?

Reflection is the ability of a program to examine its variables and structure and manipulate them at runtime.

Reflection in Go is a mechanism the language provides for dynamic type and object manipulation. You may need to examine objects, update them, call their methods, or even perform operations native to their types without knowing their types at compile time. Reflection makes all of this possible.

Various packages in Go includingencodingwhich enables you towork with JSON, andfmt, rely heavily on reflection under the hood to perform their duties.

Understanding the reflect Package in Go

Learning Golangcan be challenging due to its semantics and the robust library of packages and methods that facilitate the development of efficient software.

Thereflectpackage is one of these many packages. It consists of all the methods you need to implement reflection in Go applications.

To get started with thereflectpackage, you can simply import it like this:

The package defines two major types that lay the foundation for reflection in Go:reflect.Typeandreflect.Value.

ATypeis simply a Go type.reflect.Typeis an interface that consists of various methods for identifying different types and examining their components.

The function for checking the type of any object in Go,reflect.TypeOf, accepts any value (aninterface{}) as its only argument and returns areflect.Typevalue which represents the object’s dynamic type.

The code below demonstrates the use ofreflect.TypeOf:

The second type in thereflectpackage,reflect.Valuecan hold a value of any type. Thereflect.ValueOffunction accepts anyinterface{}and returns the interface’s dynamic value.

Here’s an example showing how to usereflect.ValueOfto inspect the values above:

To inspect the kinds and types of the values, you can use theKindandTypemethod like this:

Although the result of both function calls is the same, they are distinct.typeOfX2is basically the same thing astypeOfXbecause they are both dynamicreflect.Typevalues, butkindOfXis a constant whose value is the specific kind ofx,string.

This is why there are a finite number of kinds such asint,string,float,array, etc., but an infinite number of types as there can be several user-defined types.

Aninterface{}and areflect.Valueworks almost the same way, they can hold values of any type.

The difference between them lies in how an emptyinterface{}never exposes the native operations and methods of the value it holds. So most times you need to know the dynamic type of the value and use type assertion to access it (i.e.i.(string),x.(int), etc.) before you can perform operations with it.

In contrast, areflect.Valuehas methods that you can use to examine its contents and properties, irrespective of its type. The next section examines these two types practically and shows how they are useful in programs.

Implementing Reflection in Go Programs

Reflection is very broad and can find use in a program at any point in time. Below are some practical examples that demonstrate the usage of reflection in programs:

The above examples are some ways you can use reflection in your real-world Go programs. Thereflectpackage is very robust and you can learn more about its capabilities in the officialGo reflectdocumentation.

There can be multiple scenarios where reflection may seem ideal, but it is important to note that reflection has its own tradeoffs and can affect a program negatively when not used appropriately.

Here are some things to note about reflection:

Use Reflection When Required

Reflection is available in many languages including C# and JavaScript, and Go does well to implement the API excellently. A major advantage of reflection in Go is that you can solve problems with less code when you harness the capability of the library.

However, type safety is crucial for ensuring reliable code, and speed is another important factor for a smooth user experience. This is why you should only use reflection after weighing your options. And aim to keep your code readable and optimal.