go语言reflect.Type 和 reflect.Value 应用示例详解

目录
  • 一、使用 reflect.Type 创建实例
  • 二、使用 reflect.Value 调用函数

一、使用 reflect.Type 创建实例

在通过 reflect.TypeOf 函数获取到变量的反射类型对象之后,可以通过反射类型对象 reflect.TypeNew 函数来创建一个新的实例,注意这个实例的类型是 reflect.Type 类型的。

package main
import (
   "fmt"
   "reflect"
)
func main() {
   var zulu int
   zuluTypeOf := reflect.TypeOf(zulu)
   // 创建类型实例
   zuluIntPtr := reflect.New(zuluTypeOf)
   fmt.Printf("%T\n", zuluIntPtr)
   fmt.Printf("%v, %v\n", zuluIntPtr.Type(), zuluIntPtr.Kind())
}

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

reflect.Value
*int, ptr

二、使用 reflect.Value 调用函数

在 Go 语言的函数 讲到 Go 中函数是一等公民,函数可以保存在变量中,当 reflect.ValueOf 获取的是一个函数类型变量的反射值对象时,可以通过 reflect.ValueCall 方法调用该函数

使用反射调用函数需要将参数使用反射值对象的切片 []reflect.Value 构造后传入 Call 方法中,调用之后再通过切片 []reflect.Value 的形式返回函数的返回值。

函数只有一个返回值的情况

定义一个 add 函数,该函数有两个入参和一个返回值,先获取函数类型变量的反射值对象,再利用反射值对象调用 Call 函数,并将函数变量中函数的入参以 reflect.Value 类型切片的形式作为 Call 函数的入参即可获取函数变量中函数调用的结果。

package main
import (
   "fmt"
   "reflect"
)
func main() {
   // 定义一个变量保存 add 函数
   var victor func(x, y int) (sum int) = add
   // 获取 函数变量的反射值对象
   victorValueOf := reflect.ValueOf(victor)
   // 构造 []reflect.Value 切片参数列表
   paramValueOfSlice := []reflect.Value{reflect.ValueOf(3), reflect.ValueOf(8)}
   // 调用函数
   var resValueOfSlice []reflect.Value = victorValueOf.Call(paramValueOfSlice)
   // 遍历
   fmt.Printf("%v\n", resValueOfSlice[0])
   fmt.Printf("%T\n", resValueOfSlice[0])
}
func add(x, y int) (sum int) {
   sum = x + y
   return
}

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

11
reflect.Value

函数有两个或者多个返回值的情况

定义一个 div 函数,该函数有两个入参和两个返回值,仍然是先获取函数类型变量的反射值对象,再利用反射值对象调用 Call 函数,并将函数变量中函数的入参以 reflect.Value 类型切片的形式作为 Call 函数的入参即可获取函数变量中函数调用的结果。

该函数调用结果的切片中含有两个元素,且这两个元素的类型都是 reflect.Value

package main
import (
   "fmt"
   "reflect"
)
func main() {
   // 定义一个变量保存 add 函数
   var victor func(x, y int) (sum int, ok bool) = div
   // 获取 函数变量的反射值对象
   victorValueOf := reflect.ValueOf(victor)
   fmt.Println("当除数非 0 的情况:")
   // 构造 []reflect.Value 切片参数列表
   paramValueOfSlice := []reflect.Value{reflect.ValueOf(8), reflect.ValueOf(2)}
   // 调用函数
   var resValueOfSlice []reflect.Value = victorValueOf.Call(paramValueOfSlice)
   // 返回值切片长度
   fmt.Printf("返回值切片长度为:%v\n", len(resValueOfSlice))
   for i := 0; i < len(resValueOfSlice); i++ {
      fmt.Printf("%v, %T\n", resValueOfSlice[i], resValueOfSlice[i])
   }
   fmt.Println()
   fmt.Println("当除数为 0 的情况:")
   // 构造 []reflect.Value 切片参数列表
   paramValueOfSlice2 := []reflect.Value{reflect.ValueOf(3), reflect.ValueOf(0)}
   // 调用函数
   var resValueOfSlice2 []reflect.Value = victorValueOf.Call(paramValueOfSlice2)
   // 返回值切片长度
   fmt.Printf("返回值切片长度为:%v\n", len(resValueOfSlice2))
   for i := 0; i < len(resValueOfSlice2); i++ {
      fmt.Printf("%v, %T\n", resValueOfSlice2[i], resValueOfSlice2[i])
   }
}
func div(x, y int) (res int, ok bool) {
   if y == 0 {
      res = 0
      ok = false
   } else {
      res = x / y
      ok = true
   }
   return
}

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

返回值切片长度为:2
4, reflect.Value
true, reflect.Value
当除数为 0 的情况:
返回值切片长度为:2
0, reflect.Value
false, reflect.Value

不管是函数只有一个返回值还是多个返回值的情况,使用反射值对象调用 Call 函数获取到的函数变量中函数的调用结果都是 reflect.Value 类型的,要想获取原类型的数据,还需要将 reflect.Value 再转换成原类型。

以上就是go语言reflect.Type 和 reflect.Value 应用示例详解的详细内容,更多关于go reflect.Type reflect.Value的资料请关注我们其它相关文章!

(0)

相关推荐

  • 深入理解Golang的反射reflect示例

    目录 编程语言中反射的概念 interface 和 反射 Golang的反射reflect reflect的基本功能TypeOf和ValueOf 说明 从relfect.Value中获取接口interface的信息 已知原有类型[进行“强制转换”] 说明 未知原有类型[遍历探测其Filed] 说明 通过reflect.Value设置实际变量的值 说明 通过reflect.ValueOf来进行方法的调用 说明 Golang的反射reflect性能 小结 总结 参考链接 编程语言中反射的概念 在计算

  • Go REFLECT Library反射类型详解

    目录 一.反射概述 二.反射类型对象 基本数类型的 反射类型对象 引用数据类型的 反射类型对象 结构体的 反射类型对象 指针的 反射类型对象 一.反射概述 反射是指程序在运行期间对程序本身进行访问和修改的能力.程序在编译过程中变量会被转换为内存地址,变量名不会被编译器写入到可执行部分.在程序运行时程序无法获取自身的信息. 在静态语言中如 Java 可以在程序编译期将变量的反射信息,如字段名称.类型等信息整合到可执行文件中,并给程序提供接口访问反射信息,这样就可以在程序运行期获取类型的反射信息,并

  • Go利用反射reflect实现获取接口变量信息

    目录 引言 一.反射的规则 1.从实例到 Value 2.从实例到 Type 3.从 Type 到 Value 4.从 Value 到 Type 5.从 Value 到实例 6.从 Value 的指针到值 7.Type 指针和值的相互转换 8.Value 值的可修改性 9.根据 Go 官方关于反射的文档,反射有三大定律:9 二.反射的使用 1.已知原有类型 2.未知原有类型 总结 引言 反射是通过实体对象获取反射对象(Value.Type),然后可以操作相应的方法.在某些情况下,我们可能并不知道

  • golang 如何用反射reflect操作结构体

    背景 需要遍历结构体的所有field 对于exported的field, 动态set这个field的value 对于unexported的field, 通过强行取址的方法来获取该值(tricky?) 思路 下面的代码实现了从一个strct ptr对一个包外结构体进行取值的操作,这种场合在笔者需要用到反射的场合中出现比较多 simpleStrtuctField 函数接受一个结构体指针,因为最后希望改变其值,所以传参必须是指针.然后解引用. 接下来遍历结构体的每个field, exported字段是

  • Go语言reflect.TypeOf()和reflect.Type通过反射获取类型信息

    在 Go语言中通过调用 reflect.TypeOf 函数,我们可以从一个任何非接口类型的值创建一个 reflect.Type 值.reflect.Type 值表示着此非接口值的类型.通过此值,我们可以得到很多此非接口类型的信息.当然,我们也可以将一个接口值传递给一个 reflect.TypeOf 函数调用,但是此调用将返回一个表示着此接口值的动态类型的 reflect.Type 值. 实际上,reflect.TypeOf 函数的唯一参数的类型为 interface{},reflect.Type

  • Go语言反射reflect.Value实现方法的调用

    目录 引言 func (Value) Call 通过反射,调用方法. 通过反射,调用函数. 引言 这算是一个高级用法了,前面我们只说到对类型.变量的几种反射的用法,包括如何获取其值.其类型.以及如何重新设置新值.但是在项目应用中,另外一个常用并且属于高级的用法,就是通过reflect来进行方法[函数]的调用.比如我们要做框架工程的时候,需要可以随意扩展方法,或者说用户可以自定义方法,那么我们通过什么手段来扩展让用户能够自定义呢?关键点在于用户的自定义方法是未可知的,因此我们可以通过reflect

  • Go语言基础切片的创建及初始化示例详解

    目录 概述 语法 一.创建和初始化切片 make 字面量 二.使用切片 赋值和切片 切片增长 遍历切片 总结 总示例 示例一  两个slice是否相等 示例二 两个数字是否包含 概述 切片是一种动态数组 按需自动改变大小 与数组相比,切片的长度可以在运行时修改 语法 一.创建和初始化切片 make 使用内置函数make()创建切片: var slice []type = make([]type, len, cap) //简写: slice := make([]type, len, cap) 字面

  • Go语言学习教程之结构体的示例详解

    目录 前言 可导出的标识符 嵌入字段 提升 标签 结构体与JSON相互转换 结构体转JSON JSON转结构体 练习代码步骤 前言 结构体是一个序列,包含一些被命名的元素,这些被命名的元素称为字段(field),每个字段有一个名字和一个类型. 结构体用得比较多的地方是声明与数据库交互时需要用到的Model类型,以及与JSON数据进行相互转换.(当然,项目中任何需要多种数据结构组合在一起使用的地方,都可以选择用结构体) 代码段1:声明一个待办事项的Model类型: type Todo struct

  • C语言编程C++旋转字符操作串示例详解

    目录 旋转字符串 字符串左旋 题前认知: 暴力移位: 三步翻转: 判断字符串旋转 题前认知 字符串追加判断 旋转字符串 字符串左旋 实现一个函数,可以左旋字符串中的k个字符. 例如: ABCD左旋一个字符得到BCDA ABCD左旋两个字符得到CDAB 题前认知: 一个字符串如果就定死了.eg:char arr[]="dfdf"什么的那多没意思,一点都没有人机交互的感觉,(虽然现在人机交互适合个体,不适合集群,但也是比死板的定死字符串舒服) 所以字符串得是我们可输入的,才有可玩性,玩的不

  • Go语言基础go build命令用法及示例详解

    目录 go build 一个Go项目在GOPATH下,会有如下三个目录 使用: 注意: go build 1. 用于测试编译多个包或一个main包 2. build命令编译包丢弃非main包编译结果,只是检查是否能够被编译 3. 保留main包编译结果 一个Go项目在GOPATH下,会有如下三个目录 bin存放编译后的可执行文件 pkg存放编译后的包文件 src存放项目源文件 一般,bin和pkg目录可以不创建,go命令会自动创建(如 go install),只需要创建src目录即可. 使用:

  • Go语言基础变量的声明及初始化示例详解

    目录 一.概述 二.声明变量 三.编译器推导类型的格式[一定要赋值] 四.短变量声明并初始化 五.匿名变量--没有名字的变量 六.注意 七.案例 一.概述 变量的功能是存储用户的数据 二.声明变量 Go语言的每一个变量都拥有自己的类型,必须经过声明才能开始用 变量的声明格式: var <变量名称> [变量类型] var a int //声明一个整型类型的变量,可以保存整数数值 var b string //声明一个字符串类型的变量 var c float32 //声明一个32位浮点切片类型的变

  • Go语言基础if条件语句用法及示例详解

    目录 概述 语法 格式规则 概述 条件语句需要开发者通过指定一个或多个条件 并通过测试条件是否为 true 来决定是否执行指定语句 并在条件为 false 的情况再执行另外的语句. 语法 package main func main() { //第一种格式 if 条件表达式 { 语句1 } //第二种格式 if 初始化表达式; 条件表达式 { 语句1 } //第三种格式 if 初始化表达式; 条件表达式 { 语句1 }else{ 语句2 } //第四种格式 if 初始化表达式; 条件表达式 {

  • C语言实现生成新春福字的示例详解

    目录 主要代码 字面量以及数据结构 定义一个回调函数,刷新福字 应用初始化程序 主程序 效果展示 快新年了,支付宝扫福活动又开始了,每次都要百度找福,这次不想找了,自己写一个程序生成各种字体的福字. 主要代码 字面量以及数据结构 #define FONT_DISPLAY "福" // g_fu_label中的每一个控件都是一个福字 static GtkWidget *g_fu_label[3][3]; // 记录所有的字体family typedef struct { int n_fa

  • R语言使用cgdsr包获取TCGA数据示例详解

    目录 TCGA数据源 TCGA数据库探索工具 查看任意数据集的样本列表方式 选定数据形式及样本列表后获取感兴趣基因的信息,下载mRNA数据 选定样本列表获取临床信息 综合性获取 下载mRNA数据 获取病例列表的临床数据 从cBioPortal下载点突变信息 从cBioPortal下载拷贝数变异数据 把拷贝数及点突变信息结合画热图 TCGA数据源 众所周知,TCGA数据库是目前最综合全面的癌症病人相关组学数据库,包括的测序数据有: DNA Sequencing miRNA Sequencing P

  • C语言动态内存管理malloc柔性数组示例详解

    目录 1.1为什么存在动态内存管理 1.2动态内存管理函数 1.2.1malloc 1.2.2free 1.2.3calloc 1.2.4realloc 1.3动态内存管理函数易错点 1.3.1对NULL指针的解引用操作 1.3.2对动态开辟空间的越界访问 1.3.3对非动态开辟内存使用free释放 1.3.4使用free释放一块动态开辟内存的一部分 1.3.5对同一块动态内存多次释放 1.3.6动态开辟内存忘记释放(内存泄漏) 2.1常见相关笔试题 2.2C/C++语言中的内存开辟 2.3柔性

  • C语言实现顺序表的基本操作的示例详解

    目录 一.认识顺序表 1.线性表 2.顺序表的概念及结构 二.顺序表的基本操作(接口实现) 1.初始化顺序表 2.打印顺序表 3.尾插 4.尾删 5.扩容 6.头插 7.头删 8.任意位置插入 9.任意位置删除 10.查找某个数的位置 三.顺序表演示及代码(含源码) 1.演示效果 2.完整源代码 一.认识顺序表 1.线性表 线性表是n个具有相同特性的数据元素的有限序列,线性表是一种在实际中广泛使用的数据结构,常见的线性表有顺序表.链表.栈.队列.字符串……线性表在逻辑上是线性结构,也就是说是一条

随机推荐