
- Go - Home
- Go - Overview
- Go - Environment Setup
- Go - Program Structure
- Go - Basic Syntax
- Go - Data Types
- Go - Variables
- Go - Constants
- Go - Identifiers
- Go - Keywords
- Go - Operators
- Go - Arithmetic Operators
- Go - Assignment Operators
- Go - Relational Operators
- Go - Logical Operators
- Go - Bitwise Operators
- Go - Miscellaneous Operators
- Go - Operators Precedence
- Go Decision Making
- Go - Decision Making
- Go - If Statement
- Go - If Else Statement
- Go - Nested If Statements
- Go - Switch Statement
- Go - Select Statement
- Go Control Flow Statements
- Go - For Loop
- Go - Nested for Loops
- Go - Break Statement
- Go - Continue Statement
- Go - Goto Statement
- Go Functions
- Go - Functions
- Go - Call by Value
- Go - Call by Reference
- Go - Functions as Values
- Go - Function Closure
- Go - Function Method
- Go - Anonymous function
- Go Strings
- Go - Strings
- Go - String Length
- Go - String Concatenation
- Go - Compare Strings
- Go - Split String
- Go - Substring Extraction
- Go - String Replacement
- Go - String Interpolation
- Go - Parse Date Strings
- Go Arrays
- Go - Arrays
- Go - Multidimensional Arrays
- Go - Multidimensional Arrays
- Go - Passing Arrays to Functions
- Go - Pointers
- Go - Pointers
- Go - Array of pointers
- Go - Pointer to pointer
- Go - Passing pointers to functions
- Go Advanced Control Structures
- Go - Scope Rules
- Go - Dereferencing Pointer
- Go - Structures
- Go - Slice
- Go - Slice of Slices
- Go - Range
- Go - Maps
- Go - Recursion
- Go - Type Casting
- Go - Interfaces
- Go - Type Assertion
- Go - Error Handling
- Go - Concurrency
- Go - Regular Expression
- Go - Inheritance
- Go - Packages
- Go - Templates
- Go - Reflection
- Go - Generics
- Go File Handling
- Go - Read File By Word
- Go - Read File By Line
- Go - Read CSV Files
- Go - Delete File
- Go - Rename & Move File
- Go - Truncate a File
- Go - File Read-Write Mode W/O Truncation
- Go Miscellaneous
- Go - defer Keyword
- Go - Fmt Package
- Go - Zero Value
- Go - Import
Go - Reflection
Reflection in Go is an important feature that enables you to look inside and tweak the types and values of variables during runtime. It is supported by the reflect package, which belongs to the Go standard library. It is useful in dynamic scenarios such as serialization, deserialization, and generic programming.
Serialization/Deserialization: Reflection allows libraries such as encoding/json and encoding/xml to dynamic encoding and decoding data.
Generic Programming: Prior to Go 1.18, reflection was an important instrument for generic-like behavior implementation.
However, reflection is slower than direct type assertions or switches, and improper use (e.g., modifying unaddressable values) can cause runtime panics. Use it cautious and only when necessary.
Let's go through the following key concepts about the Reflection in Golang −
- reflect.Type: It represents a variable's type, obtained using reflect.TypeOf().
- reflect.Value: It represents a variable's value, obtained using reflect.ValueOf().
- Kind: It describes a type's category (e.g., int, string, slice) using .Kind().
- Inspecting Values: View a variable's fields (struct), elements (slice/array), or methods.
- Modifying Values: Change a variable's value if it's addressable (has a pointer).
Basic Usage of Reflection
This program demonstrates how to use Go's reflect package to inspect the type, value, and kind of a variable, check its mutability, and modify its value at runtime.
package main import ( "fmt" "reflect" ) func main() { var x float64 = 3.14 t := reflect.TypeOf(x) fmt.Println("Type:", t) v := reflect.ValueOf(x) fmt.Println("Value:", v) fmt.Println("Kind:", v.Kind()) if v.Kind() == reflect.Float64 { fmt.Println("x is a float64") } p := reflect.ValueOf(&x) e := p.Elem() if e.CanSet() { e.SetFloat(2.71) fmt.Println("Modified value of x:", x) } }
It will generate the following output −
Type: float64 Value: 3.14 Kind: float64 x is a float64 Modified value of x: 2.71
Inspecting a Struct
Inspecting a struct means using reflection to access its fields, values, and types at runtime.
The program uses reflection to analyze the 'Person' struct, displaying its type, field names, field types, and values.
package main import ( "fmt" "reflect" ) type Person struct { Name string Age int } func main() { p := Person{Name: "Alice", Age: 30} t := reflect.TypeOf(p) fmt.Println("Struct type:", t.Name()) for i := 0; i < t.NumField(); i++ { field := t.Field(i) fmt.Printf("Field %d: %s (type: %s)\n", i, field.Name, field.Type) } v := reflect.ValueOf(p) for i := 0; i < v.NumField(); i++ { fieldValue := v.Field(i) fmt.Printf("Field %d value: %v\n", i, fieldValue.Interface()) } }
It will generate the following output −
Struct type: Person Field 0: Name (type: string) Field 1: Age (type: int) Field 0 value: Alice Field 1 value: 30
Modifying a Struct Field
Modifying a struct field means involving a reflection to modify the value of a field at runtime, but the field has to be addressable and exported.
In this example, we employ reflection to locate and alter the Name field of a Person struct, updating its value from "Alice" to "Bob".
package main import ( "fmt" "reflect" ) type Person struct { Name string Age int } func main() { p := &Person{Name: "Alice", Age: 30} v := reflect.ValueOf(p).Elem() nameField := v.FieldByName("Name") if nameField.IsValid() && nameField.CanSet() { nameField.SetString("Bob") } fmt.Println("Modified person:", *p) }
It will generate the following output −
Modified person: {Bob 30}
Common Reflection Methods
Following are the common reflection methods in Golang −
- reflect.TypeOf(x): Returns the reflect.Type of x.
- reflect.ValueOf(x): Returns the reflect.Value of x.
- v.Kind(): Returns the reflect.Kind of the value v.
- v.Interface(): Converts the reflect.Value back to an interface{}.
- v.CanSet(): Checks if the value can be modified.
- v.SetX(): Modifies the value (e.g., SetInt, SetString, etc.).
- t.NumField(): Returns the number of fields in a struct.
- t.Field(i): Returns the i-th field of a struct.
Let us go through the simple examples for these common Reflection Methods
1. Zero Values and reflect.Zero
The reflect.Zero function returns a reflect.Value representing the zero value of a given type. This is useful when you need to initialize a value.
t := reflect.TypeOf(0) zeroValue := reflect.Zero(t) fmt.Println(zeroValue.Interface())
Example
The program uses reflect.Zero to create the zero value for an integer type.
package main import ( "fmt" "reflect" ) func main() { t := reflect.TypeOf(0) zeroValue := reflect.Zero(t) fmt.Println(zeroValue.Interface()) }
It will generate the following output −
0
2. Working with Functions
The reflection can be used to inspect and call functions. You can use reflect.Value.Call() to invoke a function.
func Add(a, b int) int { return a + b } func main() { funcValue := reflect.ValueOf(Add) args := []reflect.Value{reflect.ValueOf(2), reflect.ValueOf(3)} result := funcValue.Call(args) fmt.Println(result[0].Interface()) }
Example
The program invokes the Add function with two arguments using reflection.
package main import ( "fmt" "reflect" ) func Add(a, b int) int { return a + b } func main() { funcValue := reflect.ValueOf(Add) args := []reflect.Value{reflect.ValueOf(2), reflect.ValueOf(3)} result := funcValue.Call(args) fmt.Println(result[0].Interface()) }
It will generate the following output −
5
3. Working with Maps
The reflection can be used to look at and change maps. we can obtain the keys of a map with reflect.Value.MapKeys() and retrieve values with reflect.Value.MapIndex().
m := map[string]int{"a": 1, "b": 2} v := reflect.ValueOf(m) for _, key := range v.MapKeys() { value := v.MapIndex(key) fmt.Printf("Key: %v, Value: %v\n", key.Interface(), value.Interface()) }
Example
The program makes use of reflection to traverse map keys and values, printing every pair.
package main import ( "fmt" "reflect" ) func main() { m := map[string]int{"a": 1, "b": 2} v := reflect.ValueOf(m) for _, key := range v.MapKeys() { value := v.MapIndex(key) fmt.Printf("Key: %v, Value: %v\n", key.Interface(), value.Interface()) } }
It will generate the following output −
Key: a, Value: 1 Key: b, Value: 2
4. Working with Slices and Arrays
The reflection can be utilized to examine and change slices and arrays. You can utilize reflect.Value.Len() to retrieve the length and the reflect.Value.Index() to obtain elements.
s := []int{1, 2, 3} v := reflect.ValueOf(s) for i := 0; i < v.Len(); i++ { fmt.Println(v.Index(i).Interface()) }
Example
The program iterates through a slice using reflection and prints each element.
package main import ( "fmt" "reflect" ) func main() { s := []int{1, 2, 3} v := reflect.ValueOf(s) for i := 0; i < v.Len(); i++ { fmt.Println(v.Index(i).Interface()) } }
It will generate the following output −
1 2 3
5. Working with Channels
The reflection can be used to interact with channels.
ch := make(chan int, 1) v := reflect.ValueOf(ch) v.Send(reflect.ValueOf(42)) result, ok := v.Recv() if ok { fmt.Println(result.Interface()) }
Example
The program sends a value to a channel and receives it using reflection.
package main import ( "fmt" "reflect" ) func main() { ch := make(chan int, 1) v := reflect.ValueOf(ch) v.Send(reflect.ValueOf(42)) result, ok := v.Recv() if ok { fmt.Println(result.Interface()) } }
It will generate the following output −
42
6. Tag Parsing in Structs
The Struct field tags can be accessed using reflection. This is commonly used in libraries like encoding/json to parse custom tags.
type Person struct { Name string `json:"name"` Age int `json:"age"` } func main() { p := Person{} t := reflect.TypeOf(p) field, _ := t.FieldByName("Name") fmt.Println(field.Tag.Get("json")) }
Example
The program retrieves and prints the JSON tag of the Name field in the struct.
package main import ( "fmt" "reflect" ) type Person struct { Name string `json:"name"` Age int `json:"age"` } func main() { p := Person{} t := reflect.TypeOf(p) field, _ := t.FieldByName("Name") fmt.Println(field.Tag.Get("json")) }
It will generate the following output −
name
7. Handling Pointers
The reflection can be used to dereference pointers and inspect their underlying values. You can use reflect.Value.Elem() to dereference a pointer.
x := 42 p := &x v := reflect.ValueOf(p) if v.Kind() == reflect.Ptr { v = v.Elem() fmt.Println(v.Interface()) }
Example
The program dereferences a pointer using reflection and prints its value.
package main import ( "fmt" "reflect" ) func main() { x := 42 p := &x v := reflect.ValueOf(p) if v.Kind() == reflect.Ptr { v = v.Elem() fmt.Println(v.Interface()) } }
It will generate the following output −
42
8. Creating New Values
You can create new values of a given type using reflect.New(). This is useful for allocating memory.
t := reflect.TypeOf(0) v := reflect.New(t) v.Elem().SetInt(42) fmt.Println(v.Elem().Interface())
Example
The following program allocates a new integer and sets its value to 42.
package main import ( "fmt" "reflect" ) func main() { t := reflect.TypeOf(0) v := reflect.New(t) v.Elem().SetInt(42) fmt.Println(v.Elem().Interface()) }
It will generate the following output −
42
9. Handling Interfaces
Reflection can be used to inspect and manipulate interface values. You can use reflect.Value.Interface() to convert a reflect.Value back to an interface{}.
var x interface{} = 42 v := reflect.ValueOf(x) fmt.Println(v.Interface())
Example
The program retrieves an interface's underlying value using reflection and prints it.
package main import ( "fmt" "reflect" ) func main() { var x interface{} = 42 v := reflect.ValueOf(x) fmt.Println(v.Interface()) }
It will generate the following output −
42
10. Error Handling
Reflection operations can fail (e.g., accessing an invalid field or calling a non-existent method). Always check for validity using reflect.Value.IsValid() and handling errors.
v := reflect.ValueOf(nil) if v.IsValid() { fmt.Println("Value is valid") } else { fmt.Println("Value is invalid") }
Example
The program checks if a reflect.Value is valid and handles invalid cases.
package main import ( "fmt" "reflect" ) func main() { v := reflect.ValueOf(nil) if v.IsValid() { fmt.Println("Value is valid") } else { fmt.Println("Value is invalid") } }
It will generate the following output −
Value is invalid