Go REFLECT Library | 04 - 反射的值 Value

简介: Go REFLECT Library | 04 - 反射的值 Value

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

如果变量是结构体类型,那么使用 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
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"`
}
复制代码

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

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
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"`
}
复制代码

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

Int 指针变量 zulu 的反射值对象是否为空:true
Int 指针变量 zulu 的反射值对象是否有效:true
Int 指针变量 zulu 通过反射值对象获取的 zulu 指针变量指向的对象是否有效:false
m 变量中键 name 对应的值的反射值对象是否有效:false
t 结构体实例化对象的反射值获取的 balance 字段的反射值是否有效:false
t 结构体实例化对象的反射值获取的 Teach 结构体方法是否有效:false


相关文章
|
4月前
|
Go
Go to Learn Go之反射
Go to Learn Go之反射
51 8
|
4月前
|
Go 索引
internal\model\data_support.go:17:10: cannot use _ as value or type
internal\model\data_support.go:17:10: cannot use _ as value or type
|
5月前
|
JSON 人工智能 Go
go 反射的常见用法
go 反射的常见用法
51 4
|
5月前
|
存储 人工智能 Java
深入理解 go reflect - 要不要传指针
深入理解 go reflect - 要不要传指针
31 0
|
5月前
|
存储 缓存 人工智能
深入理解 go reflect - 反射为什么慢
深入理解 go reflect - 反射为什么慢
45 0
|
5月前
|
存储 人工智能 JSON
深入理解 go reflect - 反射基本原理
深入理解 go reflect - 反射基本原理
72 0
|
5月前
|
JavaScript 前端开发 Go
Go中使用反射的动态方法调用
Go中使用反射的动态方法调用
|
11天前
|
存储 监控 算法
员工上网行为监控中的Go语言算法:布隆过滤器的应用
在信息化高速发展的时代,企业上网行为监管至关重要。布隆过滤器作为一种高效、节省空间的概率性数据结构,适用于大规模URL查询与匹配,是实现精准上网行为管理的理想选择。本文探讨了布隆过滤器的原理及其优缺点,并展示了如何使用Go语言实现该算法,以提升企业网络管理效率和安全性。尽管存在误报等局限性,但合理配置下,布隆过滤器为企业提供了经济有效的解决方案。
52 8
员工上网行为监控中的Go语言算法:布隆过滤器的应用
|
1月前
|
存储 Go 索引
go语言中数组和切片
go语言中数组和切片
41 7
|
1月前
|
Go 开发工具
百炼-千问模型通过openai接口构建assistant 等 go语言
由于阿里百炼平台通义千问大模型没有完善的go语言兼容openapi示例,并且官方答复assistant是不兼容openapi sdk的。 实际使用中发现是能够支持的,所以自己写了一个demo test示例,给大家做一个参考。