代码:
使用反射完成对Cal结构体字段的修改和方法的调用
package main
import (
"fmt"
"reflect"
)
type Cal struct {
num1 float64
num2 float64
}
func (cal Cal) GetSub(name string) {
res := cal.num1 - cal.num2
fmt.Printf("%s完成了减法运算,%f-%f=%f\n", name, cal.num1, cal.num2, res)
}
func ReflectCalTest(in interface{}) {
inType := reflect.TypeOf(in)
inVal := reflect.ValueOf(in)
for i := 0; i < inType.Elem().NumField(); i {
fmt.Printf("第%d个字段名为%v,类型为%v\n", i, inType.Elem().Field(i).Name, inType.Elem().Field(i).Type)
}
inVal.Elem().Field(0).SetFloat(8.0)
inVal.Elem().Field(1).SetFloat(3.0)
var inArg []reflect.Value
inArg = append(inArg, reflect.ValueOf("Tom"))
//append(inArg, reflect.ValueOf("Lisa"))
inVal.Elem().Method(0).Call(inArg)
}
func main() {
cal := Cal{
num1: 18,
num2: 2,
}
ReflectCalTest(&cal)
}
运行后报错
panic: reflect: reflect.flag.mustBeAssignable using value obtained using unexported field
goroutine 1 [running]:
reflect.flag.mustBeAssignableSlow(0x1ae)
D:/Go/src/reflect/value.go:244 0x1c0
reflect.flag.mustBeAssignable(...)
D:/Go/src/reflect/value.go:234
reflect.Value.SetFloat(0x4dcee0, 0xc0000120b0, 0x1ae, 0x4020000000000000)
D:/Go/src/reflect/value.go:1587 0x3e
main.ReflectCalTest(0x4e65a0, 0xc0000120b0)
D:/Go/src/zwmchz/reflectdemo/test01/main.go:27 0x3cc
main.main()
D:/Go/src/zwmchz/reflectdemo/test01/main.go:47 0x67
exit status 2
查看27行后发现字段不可修改,官方文档对于CanSet()说明:只有一个Value持有值可以被寻址同时又不是来自非导出字段时,它才可以被修改。如果CanSet返回假,调用Set或任何限定类型的设置函数(如SetBool、SetInt64)都会panic。因此使用Set方法,对于值类型要求传递地址,即指针类型,且字段的访问范围应该是公有的,即首字母应该大写
由于错误是使用了非导出字段,将Cal结构字段名首字母更改为大写后,错误消失
修改后代码如下
package main
import (
"fmt"
"reflect"
)
type Cal struct {
Num1 float64
Num2 float64
}
func (cal Cal) GetSub(name string) {
res := cal.Num1 - cal.Num2
fmt.Printf("%s完成了减法运算,%f-%f=%f\n", name, cal.Num1, cal.Num2, res)
}
func ReflectCalTest(in interface{}) {
inType := reflect.TypeOf(in)
inVal := reflect.ValueOf(in)
for i := 0; i < inType.Elem().NumField(); i {
fmt.Printf("第%d个字段名为%v,类型为%v\n", i, inType.Elem().Field(i).Name, inType.Elem().Field(i).Type)
}
if inVal.Elem().Field(0).CanSet() {
inVal.Elem().Field(0).SetFloat(8.0)
fmt.Println("num1 is ok!")
} else {
fmt.Println("num1 is not ok!")
}
if inVal.Elem().Field(1).CanSet() {
inVal.Elem().Field(1).SetFloat(3.0)
fmt.Println("num2 is ok!")
} else {
fmt.Println("num2 is not ok!")
}
var inArg []reflect.Value
inArg = append(inArg, reflect.ValueOf("Tom"))
//append(inArg, reflect.ValueOf("Lisa"))
inVal.Elem().Method(0).Call(inArg)
}
func main() {
cal := Cal{
Num1: 18,
Num2: 2,
}
ReflectCalTest(&cal)
}
结果如下
第0个字段名为Num1,类型为float64
第1个字段名为Num2,类型为float64
num1 is ok!
num2 is ok!
Tom完成了减法运算,8.000000-3.000000=5.000000
您可能感兴趣的文章:
golang 结构体断言_Golang中的reflect原理
Go语言--反射(reflect)
图解 Go 反射实现原理
golang 反射_golang面试题:reflect(反射包)如何获取字段tag?为什么json包不能导出私有变量的tag?...
Golang使用reflect操作struct
活学活用golang的反射机制
golang 结构体标签_如何在Go中使用结构标签
Golang结构体中Tag的使用
Java基础篇:反射机制详解
golang json[]