非零基础自学Golang
文章目录
- 非零基础自学Golang
- 第14章 反射
- 14.3 对结构体的反射操作
- 14.3.1 获取结构体成员类型
- 14.3.2 获取结构体成员字段的值
- 14.3.3 反射执行结构体方法
第14章 反射
14.3 对结构体的反射操作
反射不仅可以获取普通类型变量的值,还可以获取结构体成员的类型、成员变量的值以及调用结构体方法。
14.3.1 获取结构体成员类型
结构体通过reflect.TypeOf获取反射类型变量后,可以调用reflect.Type对象的NumField()方法获取结构体成员的数量,调用Field()则可以根据索引返回对应结构体字段的详细信息,具体信息如下:
type StructField struct {
Name string // 字段名
PkgPath string // 字段路径
Type Type // 字段反射类型对象
Tag StructTag // 字段结构体标签
Offset uintptr // 字段在结构体中的偏移
Index []int // 字段的索引值
Anonymous bool // 是否为匿名字段
}
reflect.Type中还可以使用FieldByName(name string)通过查找字段名来获取字段信息,以及使用FieldByIndex(index []int)通过索引值来获取字段信息。
[ 动手写 14.3.1 ]
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string
Age int `json:"age"`
string
}
func main() {
person := Person{"小张", 10, "备注"}
typeOfPerson := reflect.TypeOf(person)
// 遍历所有结构体成员获取字段信息
fmt.Println("遍历结构体")
for i := 0; i < typeOfPerson.NumField(); i++ {
field := typeOfPerson.Field(i)
fmt.Printf("字段名: %v 字段标签: %v 是否是匿名字段: %v\n", field.Name, field.Tag, field.Anonymous)
}
// 通过字段名获取字段信息
if field, ok := typeOfPerson.FieldByName("Age"); ok {
fmt.Println("通过字段名")
fmt.Printf("字段名: %v , 字段标签中json: %v \n ", field.Name, field.Tag.Get("json"))
}
// 通过下标获取字段信息
field := typeOfPerson.FieldByIndex([]int{1})
fmt.Println("通过下标")
fmt.Printf("字段名: %v , 字段标签: %v \n", field.Name, field.Tag)
}
动手写14.3.1中创建了一个Person结构体,在main函数中使用Field(i)遍历获取所有字段信息,其中包括字段名、字段标签以及是否为匿名字段。
使用FieldByName()及FieldByIndex()函数获取Age字段的信息,运行结果如下:
【提示】
当我们创建结构体时,字段可以只有类型,而没有字段名,这样的字段称为匿名字段(Anonymous Field)。
14.3.2 获取结构体成员字段的值
获取结构体成员的值,我们仍需要使用reflect.ValueOf()方法获取到reflect.Value对象,使用对象的NumField()方法可以获取结构体成员的数量,使用Field()则可以根据索引返回对应结构体字段的reflect.Value反射值类型。
[ 动手写 14.3.2]
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string
Age int `json:"age"`
string
}
func main() {
person := Person{"小张", 10, "备注"}
ValueOfPerson := reflect.ValueOf(person)
fmt.Printf("person 的字段数是: %v \n", ValueOfPerson.NumField())
// 通过下标访问获取字段值
fmt.Println("Field")
field := ValueOfPerson.Field(1)
fmt.Printf("字段值: %v \n", field.Int())
// 通过字段名获取字段值
field = ValueOfPerson.FieldByName("Age")
fmt.Println("FieldByName")
fmt.Printf("字段值: %v \n", field.Interface())
// 通过下标索引获取字段值
field = ValueOfPerson.FieldByIndex([]int{0})
fmt.Println("FieldByIndex")
fmt.Printf("字段值: %v \n", field.Interface())
}
动手写14.3.2对Person结构体变量分别使用Field()、FieldByName()、FieldByIndex()三个方法来获取结构体成员的值类型对象,并打印输出变量的值,运行结果如下:
14.3.3 反射执行结构体方法
对于结构体方法,需要使用reflect.ValueOf()获取reflect.Value对象,然后调用该对象的MethodByName(Name)函数,找到想要反射调用的方法,再通过Call函数进行反射调用。
[ 动手写 14.3.3]
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string
Age int `json:"age"`
string
}
func (p Person) GetName() {
fmt.Println(p.Name)
}
func main() {
person := Person{"小张", 10, "备注"}
valueOfPerson := reflect.ValueOf(person)
// 根据名字获取方法
f := valueOfPerson.MethodByName("GetName")
// 执行结构体方法
f.Call([]reflect.Value{})
}
运行结果:
没毛病。