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

目录
  • 引言
  • func (Value) Call
  • 通过反射,调用方法。
  • 通过反射,调用函数。

引言

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

func (Value) Call

func (v Value) Call(in []Value) []Value

Call方法使用输入的参数in调用v持有的函数。例如,如果len(in) == 3,v.Call(in)代表调用v(in[0], in[1], in[2])(其中Value值表示其持有值)。如果v的Kind不是Func会panic。它返回函数所有输出结果的Value封装的切片。和go代码一样,每一个输入实参的持有值都必须可以直接赋值给函数对应输入参数的类型。如果v持有值是可变参数函数,Call方法会自行创建一个代表可变参数的切片,将对应可变参数的值都拷贝到里面。

通过反射,调用方法。

先获取结构体对象,然后调用结构体的方法。

示例代码:

package main

import (
   "fmt"
   "reflect"
)

type Person struct {
   Name string
   Age int
   Sex string
}

func (p Person)Say(msg string)  {
   fmt.Println("hello,",msg)
}
func (p Person)PrintInfo()  {
   fmt.Printf("姓名:%s,年龄:%d,性别:%s\n",p.Name,p.Age,p.Sex)
}

func (p Person) Test(i,j int,s string){
   fmt.Println(i,j,s)
}

// 如何通过反射来进行方法的调用?
// 本来可以用结构体对象.方法名称()直接调用的,
// 但是如果要通过反射,
// 那么首先要将方法注册,也就是MethodByName,然后通过反射调动mv.Call

func main() {
   p2 := Person{"王富贵",20,"男"}
   // 1. 要通过反射来调用起对应的方法,必须要先通过reflect.ValueOf(interface)来获取到reflect.Value,
   // 得到“反射类型对象”后才能做下一步处理
   getValue := reflect.ValueOf(p2)

   // 2.一定要指定参数为正确的方法名
   // 先看看没有参数的调用方法

   methodValue1 := getValue.MethodByName("PrintInfo")
   fmt.Printf("Kind : %s, Type : %s\n",methodValue1.Kind(),methodValue1.Type())
   methodValue1.Call(nil) //没有参数,直接写nil

   args1 := make([]reflect.Value, 0) //或者创建一个空的切片也可以
   methodValue1.Call(args1)

   // 有参数的方法调用
   methodValue2 := getValue.MethodByName("Say")
   fmt.Printf("Kind : %s, Type : %s\n",methodValue2.Kind(),methodValue2.Type())
   args2 := []reflect.Value{reflect.ValueOf("反射机制")}
   methodValue2.Call(args2)

   methodValue3 := getValue.MethodByName("Test")
   fmt.Printf("Kind : %s, Type : %s\n",methodValue3.Kind(),methodValue3.Type())
   args3 := []reflect.Value{reflect.ValueOf(5), reflect.ValueOf(2),reflect.ValueOf("you")}

   methodValue3.Call(args3)
}

运行结果:

Kind : func, Type : func()
姓名:王富贵,年龄:20,性别:男
姓名:王富贵,年龄:20,性别:男
Kind : func, Type : func(string)
hello, 反射机制
Kind : func, Type : func(int, int, string)
5 2 you

通过反射,调用函数。

首先我们要先确认一点,函数像普通的变量一样,之前的章节中我们在讲到函数的本质的时候,是可以把函数作为一种变量类型的,而且是引用类型。如果说Fun()是一个函数,那么f1 := Fun也是可以的,那么f1也是一个函数,如果直接调用f1(),那么运行的就是Fun()函数。

那么我们就先通过ValueOf()来获取函数的反射对象,可以判断它的Kind,是一个func,那么就可以执行Call()进行函数的调用。

示例代码:

package main

import (
   "fmt"
   "reflect"
)

func main() {
   //函数的反射
   f1 := fun1
   value := reflect.ValueOf(f1)
   fmt.Printf("Kind : %s , Type : %s\n",value.Kind(),value.Type()) //Kind : func , Type : func()

   value2 := reflect.ValueOf(fun2)
   fmt.Printf("Kind : %s , Type : %s\n",value2.Kind(),value2.Type()) //Kind : func , Type : func(int, string)

   //通过反射调用函数
   value.Call(nil)

   value2.Call([]reflect.Value{reflect.ValueOf("hello"),reflect.ValueOf(61)})

}

func fun1(){
   fmt.Println("我是函数fun1(),无参的。")
}

func fun2(s string, i int){
   fmt.Println("我是函数fun2(),有参数:",s,i)
}

运行结果:

Kind : func , Type : func()
Kind : func , Type : func(string, int)
我是函数fun1(),无参的。
我是函数fun2(),有参数: hello 61

到此这篇关于Go语言反射reflect.Value实现方法的调用的文章就介绍到这了,更多相关Go 反射方法调用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解Golang利用反射reflect动态调用方法

    编程语言中反射的概念 在计算机科学领域,反射是指一类应用,它们能够自描述和自控制.也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义. 每种语言的反射模型都不同,并且有些语言根本不支持反射.Golang语言实现了反射,反射机制就是在运行时动态的调用对象的方法和属性,官方自带的reflect包就是反射相关的,只要包含这个包就可以使用. 多插一句,

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

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

  • Go语言反射获取类型属性和方法示例

    本系列文章,我将会进一步加深对 Go 语言的讲解,更一步介绍 Go 中的包管理.反射和并发等高级特性. 前面一篇文章主要介绍了 reflect.Type 类型对象.本文将会继续介绍 Go 反射 reflect.StructField 和 reflect.Method 相关的内容. reflect.StructField 和 reflect.Method 如果变量是一个结构体,我们还可以通过结构体域类型对象 reflect.StructField 来获取结构体下字段的类型属性.Type 接口下提供

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

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

  • 图文详解go语言反射实现原理

    Go反射的实现和 interface 和 unsafe.Pointer 密切相关.如果对golang的 interface 底层实现还没有理解,可以去看我之前的文章: Go语言interface底层实现 , unsafe.Pointer 会在后续的文章中做介绍. (本文目前使用的Go环境是Go 1.12.9) interface回顾 首先我们简单的回顾一下interface的结构,总体上是: 细分下来分为有函数的 iface 和无函数的 eface (就是 interface{} ); 无函数的

  • 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),然后可以操作相应的方法.在某些情况下,我们可能并不知道

  • Java反射之通过反射获取一个对象的方法信息(实例代码)

    以下代码为一个工具类 package com.imooc.reflect; import java.lang.reflect.Method; public class ClassUtil { public static void printClassMessage(Object obj){ //要获取类的信息,首先要获取类的类类型 Class c = obj.getClass();//传递的是哪个子类的对象,c就是该子类的类类型 //获取类的名称 System.out.println("类的名称

  • Python反射和内置方法重写操作详解

    本文实例讲述了Python反射和内置方法重写操作.分享给大家供大家参考,具体如下: isinstance和issubclass isinstance(obj,cls)检查是否obj是否是类 cls 的对象,类似 type() class Foo(object): pass obj = Foo() isinstance(obj, Foo) issubclass(sub, super)检查sub类是否是 super 类的派生类 class Foo(object): pass class Bar(Fo

  • Java使用注解和反射简化编程的方法示例

    本文实例讲述了Java使用注解和反射简化编程的方法.分享给大家供大家参考,具体如下: 一 点睛 当调用大量方法,可以使用反射和注解简化编程. 二 代码 import java.lang.annotation.Annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.la

  • ES6 proxy和reflect的使用方法与应用实例分析

    本文实例讲述了ES6 proxy和reflect的使用方法.分享给大家供大家参考,具体如下: proxy和reflect都是es6为了更好的操作对象而提供的新的API,接下来探讨一下二者的作用,联系. 设计proxy,reflect的作用: proxy的作用: Proxy的设计目的在于(修改编程语言),修改某些操作方法的默认行为, 等同于在语言层面作出修改,是元编程(meta programming)  例如修改set,get方法 reflect的作用: 1,映射一些明显属于对象语言内部的方法,

  • Golang 语言高效使用字符串的方法

    01介绍 在 Golang 语言中,string 类型的值是只读的,不可以被修改.如果需要修改,通常的做法是对原字符串进行截取和拼接操作,从而生成一个新字符串,但是会涉及内存分配和数据拷贝,从而有性能开销.本文我们介绍在 Golang 语言中怎么高效使用字符串. 02字符串的数据结构 在 Golang 语言中,字符串的值存储在一块连续的内存空间,我们可以把存储数据的内存空间看作一个字节数组,字符串在 runtime 中的数据结构是一个结构体 stringStruct,该结构体包含两个字段,分别是

随机推荐