本文紧接 Go REFLECT Library | 01 - 反射的类型 Type 继续讲解通过指针的 反射类型对象
获取了指针指向的对象之后的操作
三、反射获取结构体
在通过指针的 反射类型对象
获取了指针指向的对象之后,我们就可以对这个对象进行一些操作或者获取对象信息。
指针的 反射类型对象
获取指针指向的对象的类型如果是结构体,可以通过 反射类型对象
既 reflect.Type
的一个方法来获取结构体成员信息,比如
方法 | 方法说明 |
---|---|
Field(i int) StructField | 通过索引获取结构体中对应的字段,当不是结构体或者索引越界会 panic |
NumField() int | 获取结构体中包含的字段的数量,不是结构体会 panic |
FieldByName(name string) (StrucField, bool) | 根据给定的字符串返回字符串对应的结构体字段的信息,没有找到时 bool 为 false, 当不是结构体或者索引越界会 panic |
FieldByIndex(index []int) StructField | 针对嵌套结构体,多层访问时,根据 []int 提供的每个结构体的索引依次访问,返回字段信息,没有找到返回零值,当不是结构体或者索引越界会 panic |
FieldByNameFunc(match func(string) bool) (StructField, bool) | 根据匹配函数匹配需要的字段,当不是结构体或者索引越界会 panic |
func main(){
zulu := Zulu{"stark", 33}
zuluPtr := &zulu
zuluType := reflect.TypeOf(zuluPtr)
fmt.Printf("zuluType 的类型为:%v,类型名为:%v,种类为:%vn", zuluType, zuluType.Name(), zuluType.Kind())
// 使用反射类型对象(Type)获取指针指向的对象
zuluStructByReflect := zuluType.Elem()
fmt.Printf("zuluStructByReflect 的类型为:%v,类型名为:%v,种类为:%vn", zuluStructByReflect, zuluStructByReflect.Name(), zuluStructByReflect.Kind())
// 结构体字段的数量
numField := zuluStructByReflect.NumField()
fmt.Println("反射类型对象获取的指针指向的对象的字段数量有:", numField)
// 获取第一个字段
firstField := zuluStructByReflect.Field(0)
fmt.Printf("第一个字段是:%v, 类型是: %v", firstField, (reflect.TypeOf(firstField)).Name())
}
type Zulu struct {
Name string
Age int
}
执行上述代码,输出结果如下:
代码语言:javascript复制zuluType 的类型为:*main.Zulu,类型名为:,种类为:ptr
zuluStructByReflect 的类型为:main.Zulu,类型名为:Zulu,种类为:struct
反射类型对象获取的指针指向的对象的字段数量有: 2
第一个字段是:{Name string 0 [0] false}, 类型是: StructField
zuluPtr 结构体指针指向的结构体有两个字段,并且在调用 Field(0)
方法时返回一个 StructField 结构体,该结构体包含的字段如下:
其中:
- Name:字段名称
- PkgPath:字段在结构体中的路径
- Type:字段本身的反射类型对象,类型为 reflect.Type 可以进一步获取字段的类型信息
- Tag:结构体标签
- Index:FieldByIndex 中的索引顺序
- Anonymous:表示该字段是否为匿名字段
func main(){
t := Teacher{"Stark", 33, "NYC"}
s := Stu{"Peter", 18, "HighSchool","M", t}
sPtr := &s
sReflectType := reflect.TypeOf(sPtr)
fmt.Printf("sReflectType 的类型为:%v,类型名为:%v,种类为:%vn", sReflectType, sReflectType.Name(), sReflectType.Kind())
// 使用反射类型对象(Type)获取指针指向的对象
sStructByReflect := sReflectType.Elem()
fmt.Printf("sStructByReflect 的类型为:%v,类型名为:%v,种类为:%vn", sStructByReflect, sStructByReflect.Name(), sStructByReflect.Kind())
// 结构体字段的数量
numField := sStructByReflect.NumField()
fmt.Println("反射类型对象获取的指针指向的对象的字段数量有:", numField)
// 遍历所有的字段
for i := 0; i < numField; i {
field := sStructByReflect.Field(i)
fmt.Printf("结构体的第 %v 个字段为:%vn", (i 1), field.Name)
}
// 获取内嵌结构体 Teacher 的字段
embedFieldByIndex := sStructByReflect.FieldByIndex([]int{4, 2})
fmt.Println("结构体字段的名称为:", embedFieldByIndex.Name)
fmt.Println("结构体字段的路径为:", embedFieldByIndex.PkgPath)
fmt.Println("结构体字段的类型为:", embedFieldByIndex.Type)
fmt.Println( "结构体字段的标签为:",embedFieldByIndex.Tag)
fmt.Println("结构体字段的索引为:", embedFieldByIndex.Index)
fmt.Println( "结构体字段的是否为匿名:",embedFieldByIndex.Anonymous)
}
type Stu struct {
Name string `json:"name"`
Age int `json:"age"`
Grade string `json:"grade"`
Gender string `json:"gender"`
Teacher
}
type Teacher struct {
Name string `json:"name"`
Age int `json:"age"`
Address string `json:"address"`
}
执行上述代码,输出结果如下:
代码语言:javascript复制sReflectType 的类型为:*main.Stu,类型名为:,种类为:ptr
sStructByReflect 的类型为:main.Stu,类型名为:Stu,种类为:struct
反射类型对象获取的指针指向的对象的字段数量有: 5
结构体的第 1 个字段为:Name
结构体的第 2 个字段为:Age
结构体的第 3 个字段为:Grade
结构体的第 4 个字段为:Gender
结构体的第 5 个字段为:Teacher
结构体字段的名称为: Address
结构体字段的路径为:
结构体字段的类型为: string
结构体字段的标签为: json:"address"
结构体字段的索引为: [2]
结构体字段的是否为匿名: false
在 Go 编程 | 连载 17 - 结构体方法 中提到了使用 reflect 包获取结构体标签,其实就是使用了 StructField 结构体的 Tag 字段来获取的。
标签在序列化和反序列化以及对象关系映射时都会用到结构体标签,字段调用 Tag 表返回一个 StructTag 类型
StructTag 类型的 Get 方法可以获取指定标签的内容。