Go REFLECT Library | 03 - 反射的值 Value
一、反射值对象动态获取值
在 前面两节中介绍了 Go 的 reflect
标准库中的 TypeOf
函数可以获取变量的类型信息,不仅如此,反射还可以动态获取变量的值信息甚至动态设置变量的值,获取变量的值需要使用到 reflect
标准库下的 ValueOf
函数。
ValueOf
函数返回一个 reflect.Value
类型,该类型是一个结构体。
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 中的键值对是无序的,所有每一次获取的键反射值欺骗的顺序可能是不一样的。
相关文章
- go 中 struct 是否可以比较?
- go实现常见排序算法
- 你有对象类,我有结构体,Go lang1.18入门精炼教程,由白丁入鸿儒,go lang结构体(struct)的使用EP06
- Go REFLECT Library | 04 - 反射的值 Value
- 2022-09-22:以下go语言代码输出什么?A:5、B:不能编译;C:运行时死锁。package mainimport (
- [Go疑难杂症]为什么nil不等于nil
- 「Go工具箱」推荐一个非常简单的深拷贝工具:deepcopy
- GO 中 slice 的实现原理
- GO语言初始化数据结构的方法你知道吗?
- 2023-02-24:请用go语言调用ffmpeg,解码mp4文件并保存为YUV420SP格式文件,采用YUV420P转YUV420SP的方式。
- Go 模块 verifying xxx/go.mod: checksum mismatch 问题处理
- Go-标准库-math
- Go-包管理-go get(二)
- Go语言go mod包依赖管理工具使用详解
- Go语言通过反射修改变量的值
- go test命令(Go语言测试命令)完全攻略
- Go基础之–反射详解编程语言
- Go 从入门到精通(三)字符串,时间,流程控制,函数详解编程语言
- 部署Go语言程序到Linux服务器
- Go语言反射——性能和灵活性的双刃剑
- 精通Go语言开发Redis应用(go语言redis开发)
- Linux下安装Go环境指南(linux安装go环境)
- 轻松搞定Go语言连接MySQL(go连接mysql)
- 以Go语言操作MySQL:轻松运行数据库各种查询(go语言mysql)
- 如何在Linux上安装Go语言?——简单易懂的指南(linux安装go语言)
- 关键字在SQL Server中利用GO关键字实现更优化的操作(sqlserver中go)
- 一步一步学习Go读取Oracle数据库(go读取oracle)
- 踏上oracle编程之路,Go(go oracle编程)
- Go语句让Oracle数据库管理更方便(oracle go语句)