Golang Series
Hello GoLang:
https://blog.yexca.net/archives/154
GoLang (var and const) Variables and Constants:
https://blog.yexca.net/archives/155
GoLang (func) Functions:
https://blog.yexca.net/archives/156
GoLang (slice and map) Slices and Maps:
https://blog.yexca.net/archives/160
GoLang (OOP) Object-Oriented Programming:
https://blog.yexca.net/archives/162
GoLang (reflect) Reflection: This Article
GoLang (struct tag) Struct Tags:
https://blog.yexca.net/archives/205
GoLang (goroutine) Goroutines:
https://blog.yexca.net/archives/206
GoLang (channel) Channels:
https://blog.yexca.net/archives/207
notify:
📢 This article was translated by gemini-3-flash-preview
Reflection refers to a class of applications that are capable of self-description and self-control.
pair
A Go variable consists of a type and a value part, which together form a pair.

The static type is the type the programmer sees while coding, while the concrete type is what the runtime system sees.
Whether a type assertion succeeds depends on the variable’s concrete type, not its static type. Therefore, if a read variable’s concrete type also implements a write method, it can be type-asserted as write.
Reflection is built upon types. Since static types are fixed, reflection mainly interacts with the interface type (which holds the concrete type).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| package main
import "fmt"
type ReadBook interface {
Read()
}
type WriteBook interface {
Write()
}
type Book struct {
}
func (this *Book) Read() {
fmt.Println("read Book")
}
func (this *Book) Write() {
fmt.Println("write Book")
}
func main() {
// b: pair<type:Book, value:address of book{}>
b := &Book{}
// r: pair<type:, value:>
var r ReadBook
// r: pair<type:Book, value:address of book{}>
r = b
r.Read()
var w WriteBook
w = r.(WriteBook) // This works because the concrete type of r is Book
w.Write()
}
|
TypeOf and ValueOf
reflect.TypeOf() retrieves the type from the pair, and reflect.ValueOf() retrieves the value.
1
2
3
4
5
6
7
8
9
10
11
12
| package main
import (
"fmt"
"reflect"
)
func main() {
a := 3.14
fmt.Println("type of a:", reflect.TypeOf(a)) // float64
fmt.Println("value of a:", reflect.ValueOf(a)) // 3.14
}
|
Type Conversion
Executing reflect.ValueOf() returns a variable of type reflect.Value.
Known Original Data Type
If the original data type is known, you can use a direct type assertion.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| package main
import (
"fmt"
"reflect"
)
func main() {
a := 3.14
fmt.Println("type of a:", reflect.TypeOf(a))
fmt.Println("value of a:", reflect.ValueOf(a))
value := reflect.ValueOf(a)
fmt.Printf("type of value:%T\n", value) // reflect.Value
newA := value.Interface().(float64)
fmt.Printf("type of newA:%T\n", newA) // float64
}
|
Note that type conversion must be an exact match, otherwise it will panic (e.g., when dealing with pointers).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| package main
import (
"fmt"
"reflect"
)
func main() {
a := 3.14
fmt.Println("type of a:", reflect.TypeOf(a))
fmt.Println("value of a:", reflect.ValueOf(a))
// Pass the address
point := reflect.ValueOf(&a)
fmt.Printf("type of value:%T\n", point) // reflect.Value
// Convert type to pointer
newA := point.Interface().(*float64)
fmt.Printf("type of newA:%T\n", newA) // *float64
}
|
In essence, reflection allows you to convert a “reflection type object” back into an “interface type variable”.
Unknown Original Data Type
This is achieved by iterating through fields.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
| package main
import (
"fmt"
"reflect"
)
type Person struct {
// Each line is a field
Name string
Age int
Rank float64
}
// Note: Method must be public; private methods are inaccessible
func (person Person) Sleep() {
fmt.Println("person sleep")
}
func main() {
p := Person{"zhangSan", 18, 5.2}
getFieldAndMethod(p)
}
func getFieldAndMethod(input interface{}) {
getType := reflect.TypeOf(input)
fmt.Println("type:", getType.Name())
getValue := reflect.ValueOf(input)
fmt.Println("value/AllField:", getValue)
// Get fields
numField := getValue.NumField()
for i := 0; i < numField; i++ {
fieldType := getType.Field(i)
fieldValue := getValue.Field(i).Interface()
fmt.Printf("%s: %v = %v\n", fieldType.Name, fieldType.Type, fieldValue)
}
// Get methods
numMethod := getType.NumMethod()
for i := 0; i < numMethod; i++ {
method := getType.Method(i)
fmt.Printf("%s: %v\n", method.Name, method.Type)
}
}
|
Assignment via reflect.Value
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| package main
import (
"fmt"
"reflect"
)
func main() {
a := 3.14
// Assignment is only possible if it's a pointer
pointer := reflect.ValueOf(&a)
// Point to the address to get the underlying value
newValue := pointer.Elem()
// Check if the value can be set
fmt.Println("value canSet:", newValue.CanSet())
if newValue.CanSet() {
// If it can be set
newValue.SetFloat(9.96)
// Display variable value
fmt.Println("value of a:", a) // 9.96
} else {
fmt.Println("error")
}
}
|
Calling Methods via reflect.Value
Call methods by their name string.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| package main
import (
"fmt"
"reflect"
)
type User struct {
name string
age int
}
func (user User) MethodHasArgs(a string, b int) {
fmt.Println("User MethodHasArgs")
}
func (user User) MethonNotArgs() {
fmt.Println("User MethodNotArgs")
}
func main() {
user := User{"zhangSan", 18}
value := reflect.ValueOf(user)
// Call by function name
method1 := value.MethodByName("MethodHasArgs")
// Construct arguments
args1 := []reflect.Value{reflect.ValueOf("string"), reflect.ValueOf(18)}
// Call the function
method1.Call(args1)
// Call without arguments
method2 := value.MethodByName("MethonNotArgs")
args2 := make([]reflect.Value, 0)
method2.Call(args2)
}
|
Basic Principles of Reflection
