Go Language Reflection Fundamentals and Core Principles

Understanding Reflection in Go

Reflection is a powerful mechanism that enables programs to examine and manipulate the internal properties of objects of arbitrary types during runtime. In Go, the built-in reflect package provides capabilities for dynamic type and value manipulation, allowing developers to inspect variable types, struct fields, invoke methods, and modify values even when the concrete types are unknown at compile time.

Core Reflection Concepts

The fundamental components of Go's reflection system include:

  • reflect.Type: Represents metadata about Go types, including type names, Kinds (basic types, arrays, structs, etc.), method sets, and other type-related attributes.
  • reflect.Value: Represents a specific value along with its type information, enabling read and write operations on variables while respecting Go's visibility and addressability rules.
  • Dynamic type inspection and conversion: Runtime examination of concrete types held by interface variables and their conversion to corresponding reflect.Value instances.
  • Value manipulation: Dynamic operations on various value types, including struct fields, slice elements, array items, and map key-value pairs.
  • Method and function invocation: Dynamic calling of object methods even when their concrete type are unknown at compilation time.

While reflection enables more flexible data processing logic, especially in universal libraries or scenarios requiring handling of multiple unknown types, excessive use can compromise performance and reduce code readability.

First Law of Reflection: Interface to Reflection Conversion

This law describes how to convert interface variables into reflection objects. Two core functions from the reflect package facilitate this conversion:

  • reflect.TypeOf(i interface{}) Type: Acepts an interface{} parameter and returns a reflect.Type object describing the type information of the concrete value stored in the interface variable.
  • reflect.ValueOf(i interface{}) Value: Also accepts an interface{} parameter but returns a reflect.Value object containing both type information and the actual value from the interface variable.

Example implementation:

package main

import (
	"fmt"
	"reflect"
)

func demonstrateInterfaceToReflection() {
	var sampleNumber float64 = 7.8
	typeInfo := reflect.TypeOf(sampleNumber)
	valueInfo := reflect.ValueOf(sampleNumber)

	fmt.Printf("Type information: %v\n", typeInfo)
	fmt.Printf("Value information: %v (Kind: %v)\n", valueInfo, valueInfo.Kind())
}

func main() {
	demonstrateInterfaceToReflection()
}

Second Law of Reflection: Reflection to Interface Conversion

This principle allows converting reflection objects back to interface variables. A reflect.Value object obtained through reflection can be encapsulated back into an interface{} type for use in regular Go code.

Example demonstrating this conversion:

package main

import (
	"fmt"
	"reflect"
)

func demonstrateReflectionToInterface() {
	var originalValue float64 = 9.1

	// Convert native type to reflection object
	reflectionValue := reflect.ValueOf(originalValue)

	// Convert reflection object back to interface
	interfaceValue := reflectionValue.Interface().(float64)

	fmt.Println("Original value:", originalValue)
	fmt.Println("Interface converted value:", interfaceValue)
}

func main() {
	demonstrateReflectionToInterface()
}

Third Law of Reflection: Modifying Reflection Values

To modify the value represented by a reflect.Value object, that value must be settable. Not all reflect.Value instances permit assignment or modification operations.

A value is settable if it meets these conditions:

  • It's a pointer pointing to an addressable storage location
  • It's a reference type like slices, maps, or interfaces that can accept new values
  • It's a struct field where the containing struct is addressable via pointer

Example implementation:

package main

import (
	"fmt"
	"reflect"
)

type SampleStructure struct {
	FieldOne int
	FieldTwo string
}

func demonstrateValueModification() {
	instance := SampleStructure{FieldOne: 15, FieldTwo: "World"}

	// Obtain address of the struct instance
	addressValue := reflect.ValueOf(&instance)
	// Dereference to get the struct value
	structValue := addressValue.Elem()

	// Access and modify struct fields via reflection
	firstField := structValue.FieldByName("FieldOne")
	if firstField.IsValid() && firstField.CanSet() {
		firstField.SetInt(25)
	}

	fmt.Println(instance) // Output: {25 World}
}

func main() {
	demonstrateValueModification()
}

Reflection Applications

Key applications of reflection in Go include:

  • Dynamic type inspection and conversion: Runtime detection of actual types in interface variables and conditional type assertions
  • Dynamic struct field access: Retrieval and manipulation of struct field values regardless of their visibility
  • Method invocation: Calling struct methods or type functions without knowing specific types at compile time
  • Universal library development: Creation of general-purpose tools like JSON parsers, database driveers, and serialization utilities
  • Self-inspection and metaprogramming: Programs examining and modifying their own behavior
  • Data-driven applications: Dynamic code generation based on configuration files or input sources

Considerations when using reflection include performance overhead due to additional type checking, reduced code readability, and potential security implications from improper type safety violations.

Tags: Go reflection Golang Reflect type-system

Posted on Thu, 23 Jul 2026 16:23:33 +0000 by Pascal P.