三、反射获取结构体
在通过指针的 反射类型对象
获取了指针指向的对象之后,我们就可以对这个对象进行一些操作或者获取对象信息。
指针的 反射类型对象
获取指针指向的对象的类型如果是结构体,可以通过 反射类型对象
既 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,种类为:%v\n", zuluType, zuluType.Name(), zuluType.Kind()) // 使用反射类型对象(Type)获取指针指向的对象 zuluStructByReflect := zuluType.Elem() fmt.Printf("zuluStructByReflect 的类型为:%v,类型名为:%v,种类为:%v\n", 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 } 复制代码
执行上述代码,输出结果如下:
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,种类为:%v\n", sReflectType, sReflectType.Name(), sReflectType.Kind()) // 使用反射类型对象(Type)获取指针指向的对象 sStructByReflect := sReflectType.Elem() fmt.Printf("sStructByReflect 的类型为:%v,类型名为:%v,种类为:%v\n", sStructByReflect, sStructByReflect.Name(), sStructByReflect.Kind()) // 结构体字段的数量 numField := sStructByReflect.NumField() fmt.Println("反射类型对象获取的指针指向的对象的字段数量有:", numField) // 遍历所有的字段 for i := 0; i < numField; i++ { field := sStructByReflect.Field(i) fmt.Printf("结构体的第 %v 个字段为:%v\n", (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"` } 复制代码
执行上述代码,输出结果如下:
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 方法可以获取指定标签的内容。