The essence of reflection is to obtain the type information and memory structure of the object when the program is running. Reflection is a double-edged sword. It has powerful functions but poor readability. Reflection code cannot statically find errors in the compilation stage, and the reflected code is often better than the normal code. The efficiency is 1~2 orders of magnitude lower. If reflection is used in key positions, it will directly lead to code efficiency problems. Therefore, it is not recommended to use it if it is not necessary.
Static types refer to types that can be determined at compile time (common variable declaration types are static types); dynamic types refer to types that can be determined at runtime (such as interfaces, and only interfaces have reflection).
Three steps to use reflection:
- First there is a variable of interface type
- Converting it to a reflect object is generally type or value type
- Then call the corresponding function according to different situations
TypeOf() ValueOf()
To illustrate its usage, let's take the simplest example:
package main
import (
"fmt"
"reflect"
)
func main() {
var x float64 = 3.4
fmt.Println("type : ", reflect.TypeOf(x))
fmt.Println("value : ", reflect.ValueOf(x))
}
The result of running is:
type : float64
value : 3.4
Get interface variable information
When the original type is known in advance
for example:
package main
import (
"fmt"
"reflect"
)
func main() {
var num float64 = 3.14
//接口类型变量得到一个反射类型的变量
value := reflect.ValueOf(num)
//从一个反射类型对象得到接口类型变量
conervtValue := value.Interface().(float64)
fmt.Println(conervtValue)
//pointer 包含了一个float64的指针类型
pointer := reflect.ValueOf(&num)
convertPointer := pointer.Interface().(*float64)
fmt.Println(convertPointer)
}
The result of running is:
3.14
0x1400012a008
When the original type is not known in advance
At this time, we generally need to traverse and probe the Field
for example:
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string
Age int
Gender string
}
func (p Person) Say(msg string) {
fmt.Println("hello, ", msg)
}
func (p Person) PrintInfo() {
fmt.Printf("Name: %s, Age: %d, Gender: %s", p.Name, p.Age, p.Gender)
}
func main() {
p1 := Person{"bill", 16, "Male"}
GetMessage(p1)
}
//获取input的信息 在这个函数中 输入是空接口
//代表我们并不知道input的原始类型是什么 取决于函数调用的时候掺进来什么参数
func GetMessage(input interface{}) {
getType := reflect.TypeOf(input)
fmt.Println("输入数据的类型是: ", getType.Name())
fmt.Println("输入数据的种类是: ", getType.Kind())
getValue := reflect.ValueOf(input)
fmt.Println("all fields are: ", getValue)
}
The results are as follows:
输入数据的类型是: Person
输入数据的种类是: struct
all fields are: {bill 16 Male}
In the above example, we print all the field values in one go, but if we want to print the name, type, and value of each field one by one, we should do this:
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string
Age int
Gender string
}
func (p Person) Say(msg string) {
fmt.Println("hello, ", msg)
}
func (p Person) PrintInfo() {
fmt.Printf("Name: %s, Age: %d, Gender: %s", p.Name, p.Age, p.Gender)
}
func main() {
p1 := Person{"bill", 16, "Male"}
GetMessage(p1)
}
//获取input的信息 在这个函数中 输入是空接口
//代表我们并不知道input的原始类型是什么 取决于函数调用的时候掺进来什么参数
func GetMessage(input interface{}) {
getType := reflect.TypeOf(input)
fmt.Println("输入数据的类型是: ", getType.Name())
fmt.Println("输入数据的种类是: ", getType.Kind())
getValue := reflect.ValueOf(input)
fmt.Println("all fields are: ", getValue)
//获取字段
for i := 0; i < getType.NumField(); i++ {
field := getType.Field(i)
value := getValue.Field(i).Interface()
fmt.Printf("字段名称: %s, 字段类型: %s, 字段值: %v\n ", field.Name, field.Type, value)
}
}
The result of running is:
输入数据的类型是: Person
输入数据的种类是: struct
all fields are: {bill 16 Male}
字段名称: Name, 字段类型: string, 字段值: bill
字段名称: Age, 字段类型: int, 字段值: 16
字段名称: Gender, 字段类型: string, 字段值: Male
What if we also want to get methods? The principle is similar to the above, but we need to change the field to method, for example:
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string
Age int
Gender string
}
func (p Person) Say(msg string) {
fmt.Println("hello, ", msg)
}
func (p Person) PrintInfo() {
fmt.Printf("Name: %s, Age: %d, Gender: %s", p.Name, p.Age, p.Gender)
}
func main() {
p1 := Person{"bill", 16, "Male"}
GetMessage(p1)
}
//获取input的信息 在这个函数中 输入是空接口
//代表我们并不知道input的原始类型是什么 取决于函数调用的时候掺进来什么参数
func GetMessage(input interface{}) {
getType := reflect.TypeOf(input)
fmt.Println("输入数据的类型是: ", getType.Name())
fmt.Println("输入数据的种类是: ", getType.Kind())
getValue := reflect.ValueOf(input)
fmt.Println("all fields are: ", getValue)
//获取字段
for i := 0; i < getType.NumField(); i++ {
field := getType.Field(i)
value := getValue.Field(i).Interface()
fmt.Printf("字段名称: %s, 字段类型: %s, 字段值: %v\n ", field.Name, field.Type, value)
}
//获取方法
for i := 0; i < getType.NumMethod(); i++ {
method := getType.Method(i)
fmt.Printf("方法名称: %s, 方法类型: %v\n", method.Name, method.Type)
}
}
The result of running is:
输入数据的类型是: Person
输入数据的种类是: struct
all fields are: {bill 16 Male}
字段名称: Name, 字段类型: string, 字段值: bill
字段名称: Age, 字段类型: int, 字段值: 16
字段名称: Gender, 字段类型: string, 字段值: Male
方法名称: PrintInfo, 方法类型: func(main.Person)
方法名称: Say, 方法类型: func(main.Person, string)
Reference: bilibili
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。