# Reflection

Course: [Go](https://www.devtutorials.ai/learn/go) · Section: Advanced Go
Source: https://www.devtutorials.ai/learn/go/advanced-go/reflection

> Go reflection with the reflect package: reflect.Type, reflect.Value and Kind, inspecting types and struct fields and tags, reading and setting values, and DeepEqual.

## What Is Reflection?

**Reflection** = a program looking at its own values and types **while it runs**.

With reflection, code can ask a value:

- What **type** are you?
- What **kind** of thing are you: a number, a struct, a slice?
- If you are a struct, what **fields** do you have, and what are their tags?
- Can I **change** you?

Go's `reflect` package answers these questions.

**Simple lesson:** reflection lets a program inspect values whose type it did not know when it was written.

### A Real-World Example

Think of the school's lost-and-found box.

- The office does not know in advance what will be dropped in.
- For each item, they look at it: Is it a bottle? A jacket? A book?
- For a bag, they open it and list what is inside.
- Then they write a label for it.

Now the mapping:

- **The unknown item** = a value of type `any`.
- **Looking at it** = `reflect.TypeOf` and `reflect.ValueOf`.
- **Opening the bag** = going through a struct's fields.
- **The label** = what your code prints or saves.

### Why Reflection Is Used

- **`encoding/json`** uses it to read your struct's fields and tags. See **JSON**.
- **`fmt.Println`** uses it to print any value.
- **Form and config libraries** fill structs from text.
- **Testing tools** compare deep values with `reflect.DeepEqual`.

Reflection is powerful, but use it rarely in your own code.

- It is slower than normal code.
- Mistakes show up as panics while running, not as build errors.
- Interfaces or generics are usually a better choice. See **Generics**.

## What You Will Learn

In this lesson, you will learn:

1. What reflection is and why it is used.
2. The `reflect` package: `reflect.Type` and `reflect.Value`.
3. How to inspect types and struct fields.
4. How to read values and work with dynamic data.
5. How to change a value through reflection.

## The reflect Package

### reflect.Type

**reflect.Type** = the description of a type. Get it with `reflect.TypeOf(x)`.

### reflect.Value

**reflect.Value** = the value itself, wrapped so you can inspect it. Get it with `reflect.ValueOf(x)`.

### Type vs Kind

**Kind** = the general family of a type: `int`, `string`, `struct`, `slice`, `map`, `ptr`, and so on.

Pick a value and see its Type, Kind and Value.

- **Type** is exact: `map[string]int`.
- **Kind** is the family: `map`.
- Many different types share one kind. Every struct type has the kind `struct`.

```go runnable title="TypeOf, Kind and ValueOf"
package main

import (
	"fmt"
	"reflect"
)

func main() {
	values := []any{42, 3.5, "Asha", true, []int{91, 78}, map[string]int{"maths": 91}}
	for _, v := range values {
		t := reflect.TypeOf(v)
		fmt.Println(t, "| kind:", t.Kind(), "| value:", reflect.ValueOf(v))
	}
}
```

```text
int | kind: int | value: 42
float64 | kind: float64 | value: 3.5
string | kind: string | value: Asha
bool | kind: bool | value: true
[]int | kind: slice | value: [91 78]
map[string]int | kind: map | value: map[maths:91]
```

**Simple lesson:** `TypeOf` tells you what something is, and `ValueOf` gives you the value to inspect.

## Type Inspection

### Inspecting Types

Use `Kind()` to decide what to do, like a type switch for families. See **Interfaces and Polymorphism**.

```go runnable title="Describe any value by its kind"
package main

import (
	"fmt"
	"reflect"
)

func describe(x any) string {
	v := reflect.ValueOf(x)
	switch v.Kind() {
	case reflect.Int, reflect.Int64:
		return fmt.Sprint("a whole number: ", v.Int())
	case reflect.String:
		return fmt.Sprint("text with ", v.Len(), " bytes")
	case reflect.Slice:
		return fmt.Sprint("a list of ", v.Len(), " items")
	case reflect.Map:
		return fmt.Sprint("a map with ", v.Len(), " keys")
	default:
		return "something else: " + v.Kind().String()
	}
}

func main() {
	fmt.Println(describe(7))
	fmt.Println(describe("Green Valley"))
	fmt.Println(describe([]string{"a", "b", "c"}))
	fmt.Println(describe(map[int]bool{1: true}))
	fmt.Println(describe(2.5))
}
```

```text
a whole number: 7
text with 12 bytes
a list of 3 items
a map with 1 keys
something else: float64
```

- `v.Int()`, `v.Len()` and similar methods only work for the right kinds.
- Calling the wrong one panics. That is why we check `Kind()` first.

### Inspecting Struct Fields

Press **Play** to walk through a struct's fields.

- `t.NumField()` = how many fields.
- `t.Field(i)` = one field's details: `Name`, `Type`, `Tag`.
- This is exactly how `encoding/json` finds your JSON names.

```go runnable title="Read a custom tag for a form"
package main

import (
	"fmt"
	"reflect"
)

type Admission struct {
	StudentName string `label:"Student name" required:"yes"`
	ParentPhone string `label:"Parent phone" required:"yes"`
	Hobby       string `label:"Hobby"`
}

func main() {
	t := reflect.TypeOf(Admission{})
	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		mark := ""
		if f.Tag.Get("required") == "yes" {
			mark = " *"
		}
		fmt.Println(f.Tag.Get("label") + mark)
	}
}
```

```text
Student name *
Parent phone *
Hobby
```

- One loop builds the labels for any form struct.
- Required fields get a `*`.

In this lab, keep reflection to exported fields and built-in types.

The runner does not report the names of your own types (`t.Name()`), their methods, or unexported fields the way the real `go` tool does.

**Simple lesson:** `Kind()` tells you the family, and `NumField`/`Field` let you walk through a struct and its tags.

## Value Inspection

### Reading Values

```go runnable title="Read struct field values"
package main

import (
	"fmt"
	"reflect"
)

type Book struct {
	Title string
	Pages int
	Lent  bool
}

func main() {
	b := Book{"Gitanjali", 103, true}
	v := reflect.ValueOf(b)
	t := v.Type()
	for i := 0; i < v.NumField(); i++ {
		fmt.Printf("%s = %v\n", t.Field(i).Name, v.Field(i).Interface())
	}
}
```

```text
Title = Gitanjali
Pages = 103
Lent = true
```

- `v.Field(i)` is the field's value, as a `reflect.Value`.
- `.Interface()` turns it back into a normal `any` you can print.

### Changing Values

To **change** a value, reflect on a **pointer**, then use `Elem()`.

```go runnable title="Set a field by name"
package main

import (
	"fmt"
	"reflect"
)

type Student struct {
	Name  string
	Marks int
}

func main() {
	s := Student{"Ravi", 70}
	v := reflect.ValueOf(&s).Elem()

	f := v.FieldByName("Marks")
	fmt.Println(f.CanSet())
	f.SetInt(85)
	v.FieldByName("Name").SetString("Ravi Kumar")
	fmt.Println(s)
}
```

```text
true
{Ravi Kumar 85}
```

- `reflect.ValueOf(s)` would hold a **copy**, so it cannot be set.
- `reflect.ValueOf(&s).Elem()` reaches the real struct.
- `CanSet()` tells you if a change is allowed.
- The setter must match the kind: `SetInt` for ints, `SetString` for strings.

### Working with Dynamic Data

**Dynamic data** = data whose shape is only known while the program runs.

```go runnable title="Fill a struct from text pairs"
package main

import (
	"fmt"
	"reflect"
	"strconv"
)

type Settings struct {
	School  string
	Periods int
	Debug   bool
}

func fill(target any, data map[string]string) {
	v := reflect.ValueOf(target).Elem()
	for key, text := range data {
		f := v.FieldByName(key)
		if !f.IsValid() || !f.CanSet() {
			continue
		}
		switch f.Kind() {
		case reflect.String:
			f.SetString(text)
		case reflect.Int:
			n, _ := strconv.Atoi(text)
			f.SetInt(int64(n))
		case reflect.Bool:
			f.SetBool(text == "true")
		}
	}
}

func main() {
	var s Settings
	fill(&s, map[string]string{"School": "GVS", "Periods": "8", "Debug": "true", "Colour": "blue"})
	fmt.Printf("%+v\n", s)
}
```

```text
{School:GVS Periods:8 Debug:true}
```

- `fill` works for **any** settings struct, without knowing its fields in advance.
- `IsValid()` is false for a missing field, like `Colour`, so it is skipped.
- Config and form libraries work this way.

### Deep Comparison

```go runnable title="reflect.DeepEqual"
package main

import (
	"fmt"
	"reflect"
)

func main() {
	a := []int{91, 78, 85}
	b := []int{91, 78, 85}
	c := map[string][]int{"8A": {1, 2}}
	d := map[string][]int{"8A": {1, 2}}
	fmt.Println(reflect.DeepEqual(a, b))
	fmt.Println(reflect.DeepEqual(c, d))
	fmt.Println(reflect.DeepEqual(a, []int{91, 78}))
}
```

```text
true
true
false
```

- Slices and maps cannot use `==`. See **Slices**.
- `reflect.DeepEqual` compares them element by element. Tests use it a lot.

**Easy way to remember**

- What is it? → `reflect.TypeOf(x)`, `.Kind()`
- What is in it? → `reflect.ValueOf(x)`, `.Field(i)`, `.Len()`
- Change it? → `reflect.ValueOf(&x).Elem()`, then `SetInt` / `SetString`
- Prefer interfaces or generics when you can.

**Simple lesson:** `ValueOf` reads values, `ValueOf(&x).Elem()` changes them, and `DeepEqual` compares deeply.

## TL;DR

1. **Reflection** = inspect types and values while running. Package `reflect`.
2. **reflect.Type** = `reflect.TypeOf(x)`. **reflect.Value** = `reflect.ValueOf(x)`.
3. **Kind** = the family: `int`, `string`, `slice`, `map`, `struct`, `ptr` ...
4. **Struct fields** = `NumField()`, `Field(i)` → `Name`, `Type`, `Tag.Get("json")`.
5. **Read** = `v.Field(i).Interface()`, `v.Int()`, `v.Len()`.
6. **Change** = `reflect.ValueOf(&x).Elem()`, check `CanSet()`, then `SetInt` / `SetString` / `SetBool`.
7. **DeepEqual** = compare slices, maps and structs deeply.
8. **Use rarely**: slower, and errors appear only while running.

## Common mistakes

| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
| `reflect.ValueOf(s).Field(0).SetInt(5)` | Values can always be set | Reflect on `&s`, then `Elem()` | `reflect: ... using unaddressable value` panic. |
| `v.Int()` on a string | Any getter works | Check `Kind()` first | `call of reflect.Value.Int on string Value` panic. |
| Setting an unexported field | Reflection can do anything | Only exported fields can be set | A panic. |
| Using reflection for simple jobs | It is more flexible | Interfaces or generics are clearer and faster | Slow, fragile code. |
| `==` on two slices | Slices compare like arrays | Use `reflect.DeepEqual` | A build error. |
| Confusing Type and Kind | They are the same | Kind is the family, Type is exact | Wrong checks. |

## Check Yourself

## Exercises

## What to Remember

- Reflection inspects types and values while the program runs.
- `TypeOf` gives the type, `Kind()` the family, `ValueOf` the value.
- Walk struct fields with `NumField` and `Field(i)`, and read tags with `Tag.Get`.
- To change a value, reflect on a pointer and use `Elem()`.
- Prefer interfaces and generics. Use reflection only when you must.

Next: **Context**. You will learn how to cancel work, set deadlines and time limits across goroutines.
