这是我参与「第五届青训营 」伴学笔记创作活动的第 10 天
go语言提供了一种机制,在编译时不知道类型的情况下,可更新变量,在运行时查看值,调用方法以及直接对他们的布局进行操作。这种机制称为反射(reflection)。
为什么使用反射
使用空接口,可以传任意类型的数据,但是不能修改原始值
package main
import "fmt"
type User struct {
Name string
Age int
}
func Print(inter interface{}) {
switch x := inter.(type) {
case User:
x.Name = "张三"
fmt.Println(x.Name, x.Age)
}
//user := inter.(User)
//user.Name = "xxx"
}
func PPrint(user *User) {
user.Name = "王五"
}
func main() {
user := User{"枫枫", 21}
Print(user)
fmt.Println(&user)
//PPrint(&user)
//fmt.Println(user)
}
用反射就能动态修改原始数据
反射的优缺点
- 可以动态修改数据的值
- 性能问题
- 可读性不太好
reflect包
两个很重要的方法 TypeOf,ValueOf
package main
import (
"fmt"
"reflect"
)
type User struct {
Name string `json:"name" feng:"name_xxx"`
Age int `json:"age" feng:"age_xxx"`
}
func FPrint(inter interface{}) {
t := reflect.TypeOf(inter)
v := reflect.ValueOf(inter)
//fmt.Println(t.Kind()) // 获取这个接口的底层类型
//fmt.Println(t.Elem()) // 变量的原始类型
for i := 0; i < t.NumField(); i++ {
//fmt.Println()
// 字段的类型
// 字段名
// 字段的值
// 字段的tag
fmt.Println(
t.Field(i).Type,
t.Field(i).Name,
v.Field(i),
t.Field(i).Tag.Get("feng"),
)
}
}
func main() {
user := User{"枫枫", 21}
FPrint(user)
}
修改结构体的数据
package main
import (
"fmt"
"reflect"
)
type User struct {
Name string `json:"name" feng:"name_xxx"`
Age int `json:"age" feng:"age_xxx"`
}
func FPrint(inter interface{}) {
v := reflect.ValueOf(inter)
e := v.Elem() // 必须用这个
e.FieldByName("Name").SetString("枫枫知道")
}
func main() {
user := User{"枫枫", 21}
FPrint(&user) // 必须传指针
fmt.Println(user)
}