Go REFLECT Library | 03 - 反射的值 Value

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

一、反射值对象动态获取值

在 前面两节中介绍了 Go 的 reflect 标准库中的 TypeOf 函数可以获取变量的类型信息,不仅如此,反射还可以动态获取变量的值信息甚至动态设置变量的值,获取变量的值需要使用到 reflect 标准库下的 ValueOf 函数。

ValueOf 函数返回一个 reflect.Value 类型,该类型是一个结构体。

image.png

func main(){
   t := Teacher{"Stark", 33, "NYC"}
   s := Stu{"Peter", 18, "HighSchool","M", t}
   // 获取反射值类型
   reflectValueType := reflect.ValueOf(s)
   fmt.Println(reflectValueType)
}
type Stu struct {
   // 内容保持不变
}
type Teacher struct {
    // 内容保持不变
}
复制代码

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

{Peter 18 HighSchool M {Stark 33 NYC}}
复制代码

从反射 ValueOf 获取到 s 结构体的值,称之为反射值对象(reflectValueType)的包装。反射值对象 reflectValueType 与 s 结构体值的关系就是包装与被包装的关系。

二、从反射值对象获取被包装的值

如果变量是基本数据类型,那么使用 ValueOf 函数返回的 reflect.Value 类型有以下几种方法可以获取到原类型的值,可以根据原变量存储的数据类型来使用不同的方法。

方法名以及返回值类型 方法说明
Interface() interface{} 将值以 interface{} 类型返回,并通过接口断言转换成指定的类型
Int() int64 将值以 int 类型返回,所有有符号整型均可以通过此方式返回
Uint() uint64 将值以 uint 类型返回,所有无符号整型均可以通过此方式返回
Float() float64 将值以 float64 类型返回,包括 float32
Bool() bool 将值以 bool 类型返回
Bytes() []bytes 将值以字节数组返回
String() string 将值以 string 类型返回
package main
import (
   "fmt"
   "reflect"
)
func main(){
   var zulu = 12138
   var yankee = 3.14
   var xray = "stark"
   // 获取反射值对象
   zuluVal := reflect.ValueOf(zulu)
   yankeeVal := reflect.ValueOf(yankee)
   xrayVal := reflect.ValueOf(xray)
   // 此时虽然反射值对象的 数值与原变量中存储的数值一样,但是类型不一样
   fmt.Printf("%T\n", zuluVal)
   fmt.Printf("%T\n", yankeeVal)
   fmt.Printf("%T\n", xrayVal)
   // 第一种方式将 reflect.Value 类型统一转换为 interface{},再通过类型断言转换为其他类型
   var getZuluVal = zuluVal.Interface().(int)
   var getYankeeVal = yankeeVal.Interface().(float64)
   var getXrayVal = xrayVal.Interface().(string)
   // 第二种方式 reflect.Value 类型转换为 int 类型,float64 类型和 string 类型
   var getZuluVal2 = int(zuluVal.Int())
   var getYankeeVal2 = float64(yankeeVal.Float())
   var getXrayVal2 = string(xrayVal.String())
   fmt.Printf("zulu变量的值为:%v, getZuluVal 的值为:%v, 类型为:%T, getZuluVal2 的值为:%v, 类型为:%T\n", zulu, getZuluVal, getZuluVal, getZuluVal2, getZuluVal2)
   fmt.Printf("yankee:%v, getYankeeVal 的值为:%v, 类型为:%T, getYankeeVal2 的值为:%v, 类型为:%T\n", yankee, getYankeeVal, getYankeeVal, getYankeeVal2, getYankeeVal2)
   fmt.Printf("xray变量的值为:%v, getXrayVal 的值为:%v, 类型为:%T, getXrayVal2 的值为:%v, 类型为:%T\n", xray, getXrayVal, getXrayVal, getXrayVal2, getXrayVal2)
}
复制代码

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

reflect.Value
reflect.Value
reflect.Value
zulu变量的值为:12138, getZuluVal 的值为:12138, 类型为:int, getZuluVal2 的值为:12138, 类型为:int
yankee:3.14, getYankeeVal 的值为:3.14, 类型为:float64, getYankeeVal2 的值为:3.14, 类型为:float64
xray变量的值为:stark, getXrayVal 的值为:stark, 类型为:string, getXrayVal2 的值为:stark, 类型为:string
复制代码

三、从反射值对象获取 Map 中 Key 对应的值

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

方法名以及返回值类型 方法说明
MapKeys() []Value 返回一个 reflect.Value 切片,切片元素为 Map 中的 reflect.Value 类型的 Key,当值不是 Map 或者索引越界会引发 panic
MapIndex(key Value) Value 根据键的反射值对象获取键对应的值的反射值对象
package main
import (
   "fmt"
   "reflect"
)
func main() {
   // 定义一个 Map,并赋值
   info := make(map[string]interface{})
   info["name"] = "Stark"
   info["balance"] = 999999.999
   info["address"] = []string{"NYC", "BOS"}
   // 获取 Map 的反射值对象
   infoValueOf := reflect.ValueOf(info)
   // 获取 Map 中 键的反射值对象切片
   keysSlice := infoValueOf.MapKeys()
   fmt.Println("键的反射值对象组成的切片为:", keysSlice)
   fmt.Printf("键的反射值对象组成的切片的长度为:%v\n", len(keysSlice))
   fmt.Printf("键的反射值对象组成的切片中的元素类型为:%T\n", keysSlice[0])
   fmt.Println()
   // 获取键对应的值的反射值对象,再键对应的值的获取到原类型的值
   for i := 0; i < len(keysSlice); i++ {
      fmt.Printf("键反射值切片中第 %v 个键对应的值的反射值\n", i)
      keyValueOf := infoValueOf.MapIndex(keysSlice[i])
      fmt.Printf("%v\n", keyValueOf)
      fmt.Printf("%T\n", keyValueOf)
      // 从值对象获取原类型的值
      keyName := keyValueOf.Interface()
      fmt.Printf("%v\n",keyName)
      fmt.Printf("%T\n", keyName)
      fmt.Println()
   }
}
复制代码

执行上述代码,返回结果如下:

键的反射值对象组成的切片为: [name balance address]
键的反射值对象组成的切片的长度为:3
键的反射值对象组成的切片中的元素类型为:reflect.Value
键反射值切片中第 0 个键对应的值的反射值
Stark
reflect.Value
Stark
string
键反射值切片中第 1 个键对应的值的反射值
999999.999
reflect.Value
999999.999
float64
键反射值切片中第 2 个键对应的值的反射值
[NYC BOS]
reflect.Value
[NYC BOS]
[]string
复制代码

Map 中的键值对是无序的,所有每一次获取的键反射值欺骗的顺序可能是不一样的。


相关文章
|
24天前
|
JSON 人工智能 Go
go 反射的常见用法
go 反射的常见用法
26 4
|
2月前
|
安全 算法 程序员
在go语言中使用泛型和反射
【7月更文挑战第8天】本文介绍go支持泛型后,提升了代码复用,如操作切片、映射、通道的函数,以及自定义数据结构。 泛型适用于通用数据结构和函数,减少接口使用和类型断言。
116 1
在go语言中使用泛型和反射
|
24天前
|
存储 人工智能 Java
深入理解 go reflect - 要不要传指针
深入理解 go reflect - 要不要传指针
12 0
|
24天前
|
存储 缓存 人工智能
深入理解 go reflect - 反射为什么慢
深入理解 go reflect - 反射为什么慢
12 0
|
24天前
|
存储 人工智能 JSON
深入理解 go reflect - 反射基本原理
深入理解 go reflect - 反射基本原理
30 0
|
1月前
|
JavaScript 前端开发 Go
Go中使用反射的动态方法调用
Go中使用反射的动态方法调用
|
1天前
|
安全 大数据 Go
深入探索Go语言并发编程:Goroutines与Channels的实战应用
在当今高性能、高并发的应用需求下,Go语言以其独特的并发模型——Goroutines和Channels,成为了众多开发者眼中的璀璨明星。本文不仅阐述了Goroutines作为轻量级线程的优势,还深入剖析了Channels作为Goroutines间通信的桥梁,如何优雅地解决并发编程中的复杂问题。通过实战案例,我们将展示如何利用这些特性构建高效、可扩展的并发系统,同时探讨并发编程中常见的陷阱与最佳实践,为读者打开Go语言并发编程的广阔视野。
|
4天前
|
Go
golang语言之go常用命令
这篇文章列出了常用的Go语言命令,如`go run`、`go install`、`go build`、`go help`、`go get`、`go mod`、`go test`、`go tool`、`go vet`、`go fmt`、`go doc`、`go version`和`go env`,以及它们的基本用法和功能。
14 6
|
4天前
|
存储 Go
Golang语言基于go module方式管理包(package)
这篇文章详细介绍了Golang语言中基于go module方式管理包(package)的方法,包括Go Modules的发展历史、go module的介绍、常用命令和操作步骤,并通过代码示例展示了如何初始化项目、引入第三方包、组织代码结构以及运行测试。
10 3
|
6天前
|
缓存 安全 Java
如何利用Go语言提升微服务架构的性能
在当今的软件开发中,微服务架构逐渐成为主流选择,它通过将应用程序拆分为多个小服务来提升灵活性和可维护性。然而,如何确保这些微服务高效且稳定地运行是一个关键问题。Go语言,以其高效的并发处理能力和简洁的语法,成为解决这一问题的理想工具。本文将探讨如何通过Go语言优化微服务架构的性能,包括高效的并发编程、内存管理技巧以及如何利用Go生态系统中的工具来提升服务的响应速度和资源利用率。
下一篇
DDNS