Go使用反射调用方法遇到的一些问题

在使用Go反射结构体,调用结构体的过程中遇到了一些问题,特此总结下:

1.如何通过方法名调用结构体方法

2.如何通过方法名调用指针接收者方法

3.实现接口的结构体的指针接收者方法调用

4.反射调用方法的参数和返回值处理

一、如何通过方法名调用结构体方法

先修知识:reflect.ValueOf reflect.TypeOf

package main

import (
	"fmt"
	"reflect"
)

type Obj struct {
	name string
}

func (o Obj)Show(){
	fmt.Println("Hello ",o.name)
}

func main(){
	o:=Obj{"World"}
	r:=reflect.ValueOf(o)
	m:=r.MethodByName("Show")
	m.Call(nil)
}

注意方属性可以小写,方法名必须大写,否则报错

二、如何通过方法名调用指针接收者方法

package main

import (
	"fmt"
	"reflect"
)

type Obj struct {
	name string
}

func (o *Obj)Show(){
	fmt.Println("Hello ",o.name)
}

func main(){
	o:=Obj{"World"}
	r:=reflect.ValueOf(&o)
	m:=r.MethodByName("Show")
	m.Call(nil)
}

关键在于传入ValueOf的值是结构体的地址,如果需要调用的方法是结构体子字段的方法,最外层传入地址,通过Elem()和Addr()找到方法,如:

package main

import (
	"fmt"
	"reflect"
)

type OuterObj struct {
	Inner InnerObj
}

type InnerObj struct {
	name string
}

func (o *InnerObj)Show(){
	fmt.Println("Hello ",o.name)
}

func main(){
	o:=OuterObj{InnerObj{"World"}}
	r:=reflect.ValueOf(&o)
	m:=r.Elem().FieldByName("Inner").Addr().MethodByName("Show")
	m.Call(nil)
}

三、实现接口的结构体的指针接收者方法调用

这个知识点和反射没关系,结构体实现一个接口方法可以是指针接收者和值接收者,在调用的是有一点区别

package main

import (
	"fmt"
)

type Face interface {
	A()
}

type Obj struct {

}

func (o Obj)A(){
	fmt.Println("This is method A")
}

func main(){
	var t Face
	b1:=Obj{}
	t=b1
	t.A()
}
package main

import (
	"fmt"
)

type Face interface {
	A()
}

type Obj struct {

}

func (o *Obj)A(){
	fmt.Println("This is method A")
}

func main(){
	var t Face
	b1:=Obj{}
	t=&b1
	t.A()
}

四、反射调用方法的参数和返回值处理

反射如果需要传递参数,先看第一种情况,通过ValueOf找到方法:

package main

import (
	"fmt"
	"reflect"
)

type Obj struct {
}

func (o Obj)Show(name string){
	fmt.Println("Hello ",name)
}

func main(){
	o:=Obj{}
	r:=reflect.ValueOf(o)
	m:=r.MethodByName("Show")
	params:=make([]reflect.Value,1)
	params[0]=reflect.ValueOf("World")
	m.Call(params)
}

再看通过TypeOf找到方法

package main

import (
	"fmt"
	"reflect"
)

type Obj struct {
}

func (o Obj)Show(name string){
	fmt.Println("Hello ",name)
}

func main(){
	o:=Obj{}
	r:=reflect.TypeOf(o)
	m,_:=r.MethodByName("Show")
	params:=make([]reflect.Value,2)
	params[0]=reflect.ValueOf(o)
	params[1]=reflect.ValueOf("World")
	m.Func.Call(params)
}

首先,通过TypeOf找到的方法,必须在parms第一个传入本身的Value,然后调用的地方不一样

package main

import (
	"fmt"
	"reflect"
)

type Obj struct {
}

func (o Obj)Show(name string)(string,int){
	return fmt.Sprintf("Hello %s",name),len(name)
}

func main(){
	o:=Obj{}
	r:=reflect.ValueOf(o)
	m:=r.MethodByName("Show")
	params:=make([]reflect.Value,1)
	params[0]=reflect.ValueOf("World")
	result:=m.Call(params)
	fmt.Println("Show:",result[0]," Name Length:",result[1])
}

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据