reflect.Value是通过reflect.ValueOf(X)获得的,只有当X是指针的时候,才可以通过reflec.Value修改实际变量X的值,即:要修改反射类型的对象就一定要保证其值是“addressable”的。
也就是说:要想修改一个变量的值,那么必须通过该变量的指针地址 , 取消指针的引用 。通过refPtrVal := reflect.Valueof( &var )的方式获取指针类型,你使用refPtrVal.elem( ).set(一个新的reflect.Value)来进行更改,传递给set()的值也必须是一个reflect.value。
这里需要一个方法:

解释起来就是:Elem返回接口v包含的值或指针v指向的值。如果v的类型不是interface或ptr,它会恐慌。如果v为零,则返回零值。
如果你的变量是一个指针、map、slice、channel、Array。那么你可以使用reflect.Typeof(v).Elem()来确定包含的类型。
package mainimport ( "fmt" "reflect")func main() { var num float64 = 1.2345 fmt.Println("num的数值:", num) //需要操作指针 //通过reflect.ValueOf获取num中的reflect.Value,注意,参数必须是指针才能修改其值 pointer := reflect.ValueOf(&num) newValue := pointer.Elem() fmt.Println("类型 :", newValue.Type()) //float64 fmt.Println("是否可以修改:", newValue.CanSet()) // 重新赋值 newValue.SetFloat(77) fmt.Println("新的数值:", num) //////////////////// // 如果reflect.ValueOf的参数不是指针,会如何? //尝试直接修改 //value := reflect.ValueOf(num) //value.SetFloat(6.28) //panic: reflect: reflect.Value.SetFloat using unaddressable value //fmt.Println(value.CanSet()) //false //pointer = reflect.ValueOf(num) //newValue = value.Elem() // 如果非指针,这里直接panic,“panic: reflect: call of reflect.Value.Elem on float64 Value”}运行结果:
num的数值: 1.2345类型 : float64是否可以修改: true新的数值: 77
说明
- 需要传入的参数是* float64这个指针,然后可以通过pointer.Elem()去获取所指向的Value,注意一定要是指针。如果传入的参数不是指针,而是变量,那么
通过Elem获取原始值对应的对象则直接panic通过CanSet方法查询是否可以设置返回falsenewValue.CantSet()表示是否可以重新设置其值,如果输出的是true则可修改,否则不能修改,修改完之后再进行打印发现真的已经修改了。reflect.Value.Elem() 表示获取原始值对应的反射对象,只有原始对象才能修改,当前反射对象是不能修改的也就是说如果要修改反射类型对象,其值必须是“addressable”【对应的要传入的是指针,同时要通过Elem方法获取原始值对应的反射对象】struct 或者 struct 的嵌套都是一样的判断处理方式
尝试修改结构体中的字段数值:
package mainimport ( "reflect" "fmt")type Student struct { Name string Age int School string}func main() { s1:=Student{"王二狗",19,"千锋教育"} fmt.Printf("%Tn",s1) //main.Student p1:=&s1 fmt.Printf("%Tn",p1) //*main.Student fmt.Println(s1.Name) fmt.Println((*p1).Name,p1.Name) v1:= reflect.ValueOf(&s1) // value if v1.Kind()==reflect.Ptr{ fmt.Println(v1.Elem().CanSet()) v1 = v1.Elem() } f1:=v1.FieldByName("Name") f1.SetString("韩茹") f3:=v1.FieldByName("School") f3.SetString("幼儿园") fmt.Println(s1)}运行结果:
main.Student*main.Student王二狗王二狗 王二狗true{韩茹 19 幼儿园}本文参照:
http://www.sohu.com/a/313420275_657921
https://studygolang.com/articles/12348?fr=sidebar
http://c.biancheng.net/golang/


