前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go REFLECT Library | 04 - 反射的值 Value

Go REFLECT Library | 04 - 反射的值 Value

作者头像
RiemannHypothesis
发布2022-09-28 16:24:53
6690
发布2022-09-28 16:24:53
举报
文章被收录于专栏:ElixirElixir

四、从反射值对象获取结构体字段的值

如果变量是结构体类型,那么使用 ValueOf 函数返回的 reflect.Value 类型有以下几种方法可以获取结构体中的字段的值

方法名以及返回值类型

方法说明

Field(i int) Value

根据索引,返回对应结构体字段的 reflect.Value 对象,接着可以再获取到字段的类型和值。当值不是结构体或者索引越界会引发 panic

NumberField() int

返回结构体成员字段数量,当值不是结构体或者索引越界会引发 panic

FieldByName(name string) Value

通过字段名获取指定字段的反射值对象,没有找到时返回零值,当值不是结构体或者索引越界会引发 panic

FieldByIndex(index []int) Value

多层成员访问时,通过索引切片中的索引一层层获取指定索引的反射值对象,没有找到时返回零值,当值不是结构体或者索引越界会引发 panic

FieldByNameFunc(match func(string) bool) Value

根据匹配函数匹配需要的字段,没有找到时返回零值,当值不是结构体或者索引越界会引发 panic

代码语言:javascript
复制
package main

import (
   "fmt"
   "reflect"
)

func main(){

   t := Teacher{"Stark", 33, "NYC"}
   s := Stu{"Peter", 18, "HighSchool","M", t}

   stuValueOf := reflect.ValueOf(s)
   fmt.Printf("stuValueOf 的类型为:%T\n", stuValueOf)

   // 结构体字段个数
   fmt.Printf("通过结构体反射值对象获取到结构体的字段个数为:%v\n", stuValueOf.NumField())

   // 使用不同方法获取结构体字段的反射值对象
   stuValueOfName := stuValueOf.FieldByName("Name")
   stuValueOfAge := stuValueOf.Field(1)
   stuValueOfTeaName := stuValueOf.FieldByIndex([]int{4, 0})

   fmt.Printf("stuValueOfName 的类型为:%T\n", stuValueOfName)
   fmt.Printf("stuValueOfAge 的类型为:%T\n", stuValueOfAge)
   fmt.Printf("stuValueOfTeaName 的类型为:%T\n", stuValueOfTeaName)

   // 再从字段的反射值对象获取原值,可以使用 Interface() 返回获取到接口类型在通过接口断言转换为具体类型
   // 也可以直接通过 String() Int() Float() Bool() 等方法直接进行转换
   stuName := stuValueOfName.String()
   stuAge := stuValueOfAge.Interface().(int) // 强制类型转换,从 int64 转为 int
   stuTeaName := stuValueOfTeaName.String()

   fmt.Printf("从 reflect.Value 反射值对象获取的原 s 实例化结构体的 Name 字段的值为:%v, 类型为:%T\n", stuName, stuName)
   fmt.Printf("从 reflect.Value 反射值对象获取的原 s 实例化结构体的 Age 字段的值为:%v, 类型为:%T\n", stuAge, stuAge)
   fmt.Printf("从 reflect.Value 反射值对象获取的原 s 实例化结构体的 Teacher 字段(结构体) 中的 Name 的值为:%v, 类型为:%T\n", stuTeaName, stuTeaName)

}

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
复制
stuValueOf 的类型为:reflect.Value
通过结构体反射值对象获取到结构体的字段个数为:5
stuValueOfName 的类型为:reflect.Value
stuValueOfAge 的类型为:reflect.Value
stuValueOfTeaName 的类型为:reflect.Value
从 reflect.Value 反射值对象获取的原 s 实例化结构体的 Name 字段的值为:Peter, 类型为:string
从 reflect.Value 反射值对象获取的原 s 实例化结构体的 Age 字段的值为:18, 类型为:int
从 reflect.Value 反射值对象获取的原 s 实例化结构体的 Teacher 字段(结构体) 中的 Name 的值为:Stark, 类型为:string

需要注意的是在使用 FieldByName 方法获取指定名字的结构体字段时,入参要写大写的字段名,不要写 json 标签中的字段名。

五、反射值对象空判断和有效性判断

上篇文章中讲到了在获取了结构体字段的反射值对象或者是基本数据类型变量的反射值对象之后获取原数据的操作,但是在获取之前为避免报错可以先进行值是否为空判断或者有效性的判断。

值是否为空判断和有效性判断需要用到 reflect.Value 反射值对象的下面两个方法:

方法名以及返回值

方法说明

IsNil() bool

返回值是否为 nil,如果值类型不是通道 channel、函数、接口、map、指针或者切片时会发生 panic 错误

IsValid() bool

判断值是否有效,当值本身非法时,返回 false,如果返回值对象不包含任何值,值为 nil

代码语言:javascript
复制
package main

import (
   "fmt"
   "reflect"
)

func main() {

   // 判断结构体指针的反射值对象是否有效
   var zulu *int
   zuluValueOf := reflect.ValueOf(zulu)
   fmt.Printf("Int 指针变量 zulu 的反射值对象是否为空:%v\n", zuluValueOf.IsNil())
   fmt.Printf("Int 指针变量 zulu 的反射值对象是否有效:%v\n", zuluValueOf.IsValid())
   // 空指针
   fmt.Printf("Int 指针变量 zulu 通过反射值对象获取的 zulu 指针变量指向的对象是否有效:%v\n", zuluValueOf.Elem().IsValid())

   // 判断 Map 的 键是否有效
   m := map[string]string{}
   mValueOf := reflect.ValueOf(m)
   // 通过字符串类型的键 name 的 反射值对象获取该键对应的值的反射值对象
   kValueOf := mValueOf.MapIndex(reflect.ValueOf("name"))
   fmt.Printf("m 变量中键 name 对应的值的反射值对象是否有效:%v\n", kValueOf.IsValid())

   // 实例化一个 Teacher 结构体
   t := Teacher{"Stark", 33, "NYC"}

   tValueOf := reflect.ValueOf(t)

   // 获取结构体中不存在的字段
   balanceValueOf := tValueOf.FieldByName("Balance")
   methodValueOf := tValueOf.MethodByName("Teach")
   fmt.Printf("t 结构体实例化对象的反射值获取的 balance 字段的反射值是否有效:%v\n", balanceValueOf.IsValid())
   fmt.Printf("t 结构体实例化对象的反射值获取的 Teach 结构体方法是否有效:%v\n", methodValueOf.IsValid())


}

type Teacher struct {
   Name string `json:"name"`
   Age int `json:"age"`
   Address string `json:"address"`
}

执行上述代码,输出结果如下:

代码语言:javascript
复制
Int 指针变量 zulu 的反射值对象是否为空:true
Int 指针变量 zulu 的反射值对象是否有效:true
Int 指针变量 zulu 通过反射值对象获取的 zulu 指针变量指向的对象是否有效:false
m 变量中键 name 对应的值的反射值对象是否有效:false
t 结构体实例化对象的反射值获取的 balance 字段的反射值是否有效:false
t 结构体实例化对象的反射值获取的 Teach 结构体方法是否有效:false
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-08-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 四、从反射值对象获取结构体字段的值
  • 五、反射值对象空判断和有效性判断
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档