Menu
Coddy logo textTech

Reflection Basics

Part of the Object Oriented Programming section of Coddy's GO journey — lesson 83 of 107.

Reflection allows a program to examine and manipulate its own structure at runtime. Go's reflect package provides this capability, enabling you to inspect types, read struct fields, and call methods dynamically.

The two core types in reflection are reflect.Type and reflect.Value. You obtain them using reflect.TypeOf() and reflect.ValueOf():

import "reflect"

type Person struct {
    Name string
    Age  int
}

p := Person{Name: "Alice", Age: 30}

t := reflect.TypeOf(p)
v := reflect.ValueOf(p)

fmt.Println(t.Name())       // Person
fmt.Println(t.Kind())       // struct
fmt.Println(v.NumField())   // 2

You can iterate over struct fields to examine their names, types, and values:

for i := 0; i < t.NumField(); i++ {
    field := t.Field(i)
    value := v.Field(i)
    fmt.Printf("%s: %v\n", field.Name, value)
}
// Output:
// Name: Alice
// Age: 30

Reflection is powerful but comes with trade-offs: it bypasses compile-time type checking, runs slower than direct access, and makes code harder to understand. Use it sparingly for tasks like JSON marshaling, ORM mapping, or building generic utilities where the type isn't known at compile time.

challenge icon

Challenge

Easy

Let's build a struct inspector that uses reflection to examine any struct and report its structure! This is a practical use case for reflection—creating utilities that work with types unknown at compile time.

You'll organize your code across two files:

  • inspector.go: Create your reflection-based inspection utility.

    Build a function InspectStruct(v any) string that uses the reflect package to examine any struct passed to it. Your function should return a formatted report containing:

    • The struct's type name
    • The struct's kind (should be "struct")
    • The number of fields
    • For each field: the field name, its type, and its current value

    The output format should be:

    Type: [TypeName]
    Kind: struct
    Fields: [count]
    - [FieldName] ([FieldType]): [Value]
    - [FieldName] ([FieldType]): [Value]
    ...

    Use reflect.TypeOf() to get type information and reflect.ValueOf() to access field values. Iterate through fields using NumField(), Field(i) on the type for metadata, and Field(i) on the value for actual values.

  • main.go: Define sample structs and use your inspector.

    Read a struct type (product or employee) and its field values, then create the appropriate struct and inspect it.

    For product: Create a Product struct with Name (string), Price (float64), and InStock (bool) fields. Read the name, price, and stock status.

    For employee: Create an Employee struct with ID (int), Name (string), and Department (string) fields. Read the ID, name, and department.

    Pass the created struct to InspectStruct and print the result.

The following inputs will be provided:

  • Line 1: Struct type (product or employee)
  • Following lines: Field values for that struct type

For example, given:

product
Laptop
999.99
true

Your output should be:

Type: Product
Kind: struct
Fields: 3
- Name (string): Laptop
- Price (float64): 999.99
- InStock (bool): true

And given:

employee
42
Alice Johnson
Engineering

Your output should be:

Type: Employee
Kind: struct
Fields: 3
- ID (int): 42
- Name (string): Alice Johnson
- Department (string): Engineering

And given:

product
Headphones
79.50
false

Your output should be:

Type: Product
Kind: struct
Fields: 3
- Name (string): Headphones
- Price (float64): 79.5
- InStock (bool): false

Notice how your inspector works with different struct types without knowing their structure in advance—this is the power of reflection! The same InspectStruct function handles both Product and Employee structs dynamically.

Cheat sheet

The reflect package enables programs to examine and manipulate their own structure at runtime.

The two core types are reflect.Type and reflect.Value, obtained using reflect.TypeOf() and reflect.ValueOf():

import "reflect"

type Person struct {
    Name string
    Age  int
}

p := Person{Name: "Alice", Age: 30}

t := reflect.TypeOf(p)
v := reflect.ValueOf(p)

fmt.Println(t.Name())       // Person
fmt.Println(t.Kind())       // struct
fmt.Println(v.NumField())   // 2

Iterate over struct fields to examine their names, types, and values:

for i := 0; i < t.NumField(); i++ {
    field := t.Field(i)
    value := v.Field(i)
    fmt.Printf("%s: %v\n", field.Name, value)
}
// Output:
// Name: Alice
// Age: 30

Reflection bypasses compile-time type checking, runs slower than direct access, and makes code harder to understand. Use it for tasks like JSON marshaling, ORM mapping, or building generic utilities where the type isn't known at compile time.

Try it yourself

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

// Product struct with Name, Price, and InStock fields
type Product struct {
	Name    string
	Price   float64
	InStock bool
}

// Employee struct with ID, Name, and Department fields
type Employee struct {
	ID         int
	Name       string
	Department string
}

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Read the struct type
	structType, _ := reader.ReadString('\n')
	structType = strings.TrimSpace(structType)

	if structType == "product" {
		// Read product fields
		name, _ := reader.ReadString('\n')
		name = strings.TrimSpace(name)

		priceStr, _ := reader.ReadString('\n')
		priceStr = strings.TrimSpace(priceStr)
		price, _ := strconv.ParseFloat(priceStr, 64)

		inStockStr, _ := reader.ReadString('\n')
		inStockStr = strings.TrimSpace(inStockStr)
		inStock, _ := strconv.ParseBool(inStockStr)

		// TODO: Create a Product struct with the read values
		// TODO: Call InspectStruct with the product and print the result

	} else if structType == "employee" {
		// Read employee fields
		idStr, _ := reader.ReadString('\n')
		idStr = strings.TrimSpace(idStr)
		id, _ := strconv.Atoi(idStr)

		name, _ := reader.ReadString('\n')
		name = strings.TrimSpace(name)

		department, _ := reader.ReadString('\n')
		department = strings.TrimSpace(department)

		// TODO: Create an Employee struct with the read values
		// TODO: Call InspectStruct with the employee and print the result

	}
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming