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


相关文章
|
10月前
|
Go
Go to Learn Go之反射
Go to Learn Go之反射
86 8
|
10月前
|
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
|
11月前
|
JSON 人工智能 Go
go 反射的常见用法
go 反射的常见用法
99 4
|
11月前
|
存储 人工智能 Java
深入理解 go reflect - 要不要传指针
深入理解 go reflect - 要不要传指针
57 0
|
11月前
|
存储 缓存 人工智能
深入理解 go reflect - 反射为什么慢
深入理解 go reflect - 反射为什么慢
91 0
|
11月前
|
存储 人工智能 JSON
深入理解 go reflect - 反射基本原理
深入理解 go reflect - 反射基本原理
144 0
|
11月前
|
JavaScript 前端开发 Go
Go中使用反射的动态方法调用
Go中使用反射的动态方法调用
|
5月前
|
编译器 Go
揭秘 Go 语言中空结构体的强大用法
Go 语言中的空结构体 `struct{}` 不包含任何字段,不占用内存空间。它在实际编程中有多种典型用法:1) 结合 map 实现集合(set)类型;2) 与 channel 搭配用于信号通知;3) 申请超大容量的 Slice 和 Array 以节省内存;4) 作为接口实现时明确表示不关注值。此外,需要注意的是,空结构体作为字段时可能会因内存对齐原因占用额外空间。建议将空结构体放在外层结构体的第一个字段以优化内存使用。
|
5月前
|
运维 监控 算法
监控局域网其他电脑:Go 语言迪杰斯特拉算法的高效应用
在信息化时代,监控局域网成为网络管理与安全防护的关键需求。本文探讨了迪杰斯特拉(Dijkstra)算法在监控局域网中的应用,通过计算最短路径优化数据传输和故障检测。文中提供了使用Go语言实现的代码例程,展示了如何高效地进行网络监控,确保局域网的稳定运行和数据安全。迪杰斯特拉算法能减少传输延迟和带宽消耗,及时发现并处理网络故障,适用于复杂网络环境下的管理和维护。