Go REFLECT Library | 02 - 反射的类型 Type

2022-09-28 16:17:19 浏览数 (1)

本文紧接 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

代码语言:javascript复制
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:表示该字段是否为匿名字段
代码语言:javascript复制
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 方法可以获取指定标签的内容。

0 人点赞