|
|
51CTO旗下网站
|
|
移动端

9.2.2 通过反射修改设置值

《Go语言编程入门与实战技巧》第9章接口与反射,本章需要注意设计类型时确认类型的本质是原始的还是非原始的。接口是声明了一组行为并支持多态的类型,嵌入类型提供了扩展类型的能力,而无须使用继承。本节为大家介绍通过反射修改设置值。

作者:黄靖钧来源:电子工业出版社|2018-09-23 09:32

9.2.2  通过反射修改设置值

假设要把下面例子中x的值改为3.1415,Value有一些方法可以完成这个任务,但是必须小心使用v.SetFloat(3.1415),这将产生一个错误:reflect.Value.SetFloat using unaddressable value。

  1. // 示例代码9-6  
  2. package main  
  3.  
  4. import (  
  5.     "fmt"  
  6.     "reflect"  
  7. )  
  8.  
  9. func main() {  
  10.     var x float64 = 3.1415  
  11.     v :reflect.ValueOf(x)  
  12.     // 设置一个值:  
  13.     // v.SetFloat(3.1415)   
  14.     // 上面代码会产生错误,返回:  
  15.     // Panic: reflect.Value.SetFloat using unaddressable value  
  16.     fmt.Println("v:", v.CanSet())  
  17.     v = reflect.ValueOf(&x) // 注意:取x的地址  
  18.     fmt.Println("v的类型:", v.Type())  
  19.     fmt.Println("v:", v.CanSet())  
  20.     vv = v.Elem()  
  21.     fmt.Println("v的Elem是:", v)  
  22.     fmt.Println("v:", v.CanSet())  
  23.     v.SetFloat(3.1415) // 编译通过  
  24.     fmt.Println(v.Interface())  
  25.     fmt.Println(v)  
  26. }  

原因是v不是可设置的(这里并不是说值不可寻址),是否可设置是Value的一个属性,并且不是所有的反射值都有这个属性:可以使用CanSet()方法测试是否可设置。

在例子中可以看到v.CanSet()返回false:settability of v: false,当v := reflect.ValueOf(x)函数通过传递一个x副本创建了v时,那么v的改变并不能更改原始的x。要想v的更改能作用到x,那就必须传递x的地址v = reflect.ValueOf(&x)。

通过Type()可以看到v现在的类型是*float64,并且仍然是不可设置的。要想让其可设置需要使用Elem()函数,这将间接地使用指针v = v.Elem(),现在v.CanSet()返回true,并且v.SetFloat(3.1415)设置成功了!

  1. // 示例代码9-7  
  2. package main  
  3.  
  4. import (  
  5.     "fmt"  
  6.     "reflect"  
  7. )  
  8.  
  9. func main() {  
  10.     var x float64 = 3.4  
  11.     v :reflect.ValueOf(x)  
  12.     // 设置一个值:  
  13.     // v.SetFloat(3.1415)  
  14.     // 同样是错误,Panic: reflect.Value.SetFloat using unaddressable value  
  15.     fmt.Println("v:", v.CanSet())  
  16.     v = reflect.ValueOf(&x) // 注意:取x的地址  
  17.     fmt.Println("v的类型:", v.Type())  
  18.     fmt.Println("v:", v.CanSet())  
  19.     vv = v.Elem()  
  20.     fmt.Println("v的Elem是:", v)  
  21.     fmt.Println("v:", v.CanSet())  
  22.     v.SetFloat(3.1415) // 通过  
  23.     fmt.Println(v.Interface())  
  24.     fmt.Println(v)  
  25. }  
  26. /*  
  27. 返回:  
  28. v:false  
  29. v的类型是:*float64  
  30. v:false  
  31. v的Elem是:<float64 Value> 
  32. v:true  
  33. 3.1415  
  34. <float64 Value> 
  35. */  

反射中有些内容是需要用地址去改变它的状态的。


喜欢的朋友可以添加我们的微信账号:

51CTO读书频道二维码


51CTO读书会第9群:808517103

【责任编辑:book TEL:(010)68476606】

回书目   上一节   下一节
点赞 0
分享:
大家都在看
猜你喜欢

读 书 +更多

数据库系统概念

本书是数据库系统方面的经典教材之一。国际上许多著名大学包括斯坦福大学、耶鲁大学、得克萨斯大学、康奈尔大学、伊利诺伊大学、印度理工学...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊