欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

go语言通过反射创建结构体、赋值、并调用对应的操作

程序员文章站 2022-06-19 13:44:34
我就废话不多说了,大家还是直接看代码吧~package mainimport ("fmt""reflect""testing")type call struct {num1 intnum2 int}f...

我就废话不多说了,大家还是直接看代码吧~

package main
import (
	"fmt"
	"reflect"
	"testing"
)
type call struct {
	num1 int
	num2 int
}
func (call call) getsub(name string){
	fmt.printf("%v 完成了减法运算,%v - %v = %v \n", name, call.num1, call.num2, call.num1 - call.num2)
}
func (call *call) getsum(name string){
	fmt.printf("%v 完成了加法运算,%v + %v = %v \n", name, call.num1, call.num2, call.num1 + call.num2)
}
func testreflect(t *testing.t) {
	var (
		call *call
		rvalues []reflect.value
		rvalues2 []reflect.value
	)
	ptrtype := reflect.typeof(call) //获取call的指针的reflect.type
	truetype := ptrtype.elem() //获取type的真实类型
	ptrvalue := reflect.new(truetype) //返回对象的指针对应的reflect.value
	call = ptrvalue.interface().(*call)
	truevalue := ptrvalue.elem() //获取真实的结构体类型
	truevalue.fieldbyname("num1").setint(123)//设置对象属性,注意这个一定要是真实的结构类型的reflect.value才能调用,指针类型reflect.value的会报错
	//ptrvalue.fieldbyname("num2").setint(23)
	truevalue.fieldbyname("num2").setint(23)
	//rvalues = make([]reflect.value, 0)
	rvalues = append(rvalues, reflect.valueof("xiaopeng"))//调用对应的方法
	fmt.println(rvalues)
	truevalue.methodbyname("getsub").call(rvalues)
	/*
	fixme 在反射中,指针的方法不可以给实际类型调用,实际类型的方法可以给指针类型调用,因为go语言对这种操作做了封装
	所以下面一句是没问题的
	下下一句会运行时报错
	 */
	//ptrvalue.methodbyname("getsub").call(rvalues)
	//truevalue.methodbyname("getsum").call(append(rvalues2, reflect.valueof("hiram")))
	ptrvalue.methodbyname("getsum").call(append(rvalues2, reflect.valueof("hiram")))
	fmt.println(call)
	
	/*
	fixme 在实际使用中  指针和实体都能相互转换,不会影响调用
	但是指针的方法在方法体内的操作会影响到结构体本身属性
	而实体的方法不会,因为go对于结构体、数组、基本类型都是值传递
	 */
	call.getsub("aaa")
	(*call).getsub("bbb")
	call.getsum("ccc")
	(*call).getsum("ddd")
}

补充:golang 反射 reflect 设置 struct 字段

说明1 reflect.value区分canset和can not set

所以, 必须要返回成can set的reflect.value

如:

s := reflect.valueof(&t).elem()

然后就可以happy的设值了, 可是不能随便设值的, 一个通用的方法就是使用set(v value)方法,

说明2 将值转成reflect.value类型

下面的这段代码就是转成value类型

slicevalue := reflect.valueof([]int{1, 2, 3}) // 这里将slice转成reflect.value类型

说明3 reflect.valueof 参数必须是一个 指针 或 interface elem()才可以正常调用

func (value) elem func (v value) elem() value

elem returns the value that the interface v contains or that the pointer v points to. it panics if v's kind is not interface or ptr. it returns the zero value if v is nil.

elem返回接口v包含的值或指针v指向的值。 如果v的kind不是interface或ptr,它会感到恐慌。 如果v为零,它将返回零值。

实例代码

代码1:

func destroy(subj interface{}) {
	stype := reflect.valueof(subj).elem()
	field := stype.fieldbyname("status")
	if field.isvalid() {
		field.setstring("destroyed")
	}
} 
 
func testdestroy(t *testing.t) {
	// initialize data
	jaeger := jaeger{name: "cherno alpha", country: "ru", status: "active"}
	kaiju := kaiju{alias: "scissure", origin: "sydney", status: "unknown"}
	shatterdome := shatterdome{location: "lima"}
 
	// destroy everything
	destroy(&jaeger)
	destroy(&kaiju)
	destroy(&shatterdome)
 
	// check the result
	if jaeger.status != "destroy" {
		t.error("jaeger was not destroyed")
	}
	if kaiju.status != "destroy" {
		t.error("kaiju was not destroyed")
	}
}

代码2:

type t struct {
    age int
    name string
    children []int
}
t := t{12, "someone-life", nil}
s := reflect.valueof(&t).elem()
 
s.field(0).setint(123) // 内置常用类型的设值方法
slicevalue := reflect.valueof([]int{1, 2, 3}) // 这里将slice转成reflect.value类型
s.fieldbyname("children").set(slicevalue)
 

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。如有错误或未考虑完全的地方,望不吝赐教。