Go语言反射reflect深入理解(5)

第 18 行,(int)(nil) 的含义是将 nil 转换为 int,也就是int 类型的空指针。此行将 nil 转换为 int 类型,并取指针指向元素。由于 nil 不指向任何元素,*int 类型的 nil 也不能指向任何元素,值不是有效的。因此这个反射值使用 Isvalid() 判断时返回 false。

第 21 行,实例化一个结构体。

第 24 行,通过 FieldByName 查找 s 结构体中一个空字符串的成员,如成员不存在,IsValid() 返回 false。

第 27 行,通过 MethodByName 查找 s 结构体中一个空字符串的方法,如方法不存在,IsValid() 返回 false。

第 30 行,实例化一个 map,这种写法与 make 方式创建的 map 等效。

第 33 行,MapIndex() 方法能根据给定的 reflect.Value 类型的值查找 map,并且返回查找到的结果。

IsNil() 常被用于判断指针是否为空;IsValid() 常被用于判定返回值是否有效。

通过反射修改变量的值

使用 reflect.Value 对包装的值进行修改时,需要遵循一些规则。如果没有按照规则进行代码设计和编写,轻则无法修改对象值,重则程序在运行时会发生宕机。

判断及获取元素的相关方法

使用 reflect.Value 取元素、取地址及修改值的属性方法请参考下表。

反射值对象的判定及获取元素的方法 方法名备 注
Elem() Value   取值指向的元素值,类似于语言层*操作。当值类型不是指针或接口时发生宕 机,空指针时返回 nil 的 Value  
Addr() Value   对可寻址的值返回其地址,类似于语言层&操作。当值不可寻址时发生宕机  
CanAddr() bool   表示值是否可寻址  
CanSet() bool   返回值能否被修改。要求值可寻址且是导出的字段  
值修改相关方法

使用 reflect.Value 修改值的相关方法如下表所示。

反射值对象修改值的方法 Set(x Value)将值设置为传入的反射值对象的值
Setlnt(x int64)   使用 int64 设置值。当值的类型不是 int、int8、int16、 int32、int64 时会发生宕机  
SetUint(x uint64)   使用 uint64 设置值。当值的类型不是 uint、uint8、uint16、uint32、uint64 时会发生宕机  
SetFloat(x float64)   使用 float64 设置值。当值的类型不是 float32、float64 时会发生宕机  
SetBool(x bool)   使用 bool 设置值。当值的类型不是 bod 时会发生宕机  
SetBytes(x []byte)   设置字节数组 []bytes值。当值的类型不是 []byte 时会发生宕机  
SetString(x string)   设置字符串值。当值的类型不是 string 时会发生宕机  

以上方法,在 reflect.Value 的 CanSet 返回 false 仍然修改值时会发生宕机。

在已知值的类型时,应尽量使用值对应类型的反射设置值。

值可修改条件之一:可被寻址

通过反射修改变量值的前提条件之一:这个值必须可以被寻址。简单地说就是这个变量必须能被修改。示例代码如下:

package main import "reflect" func main() { //声明整形变量a并赋初值 var a int = 1024 //获取变量a的反射值对象 rValue := reflect.ValueOf(a) //尝试将a修改为1(此处会崩溃) rValue.SetInt(1) }

程序运行崩溃,打印错误

panic: reflect: reflect.Value.SetInt using unaddressable value

报错意思是:SetInt正在使用一个不能被寻址的值。从 reflect.ValueOf 传入的是 a 的值,而不是 a 的地址,这个 reflect.Value 当然是不能被寻址的。将代码修改一下,重新运行:

package main import ( "fmt" "reflect" ) func main() { //声明整形变量a并赋初值 var a int = 1024 //获取变量a的反射值对象 rValue := reflect.ValueOf(&a) //取出a地址的元素(a的值) rValue = rValue.Elem() //尝试将a修改为1 rValue.SetInt(1) //打印a的值 fmt.Println(rValue.Int()) }

代码输出

1

下面是对代码的分析:

第 14 行中,将变量 a 取值后传给 reflect.ValueOf()。此时 reflect.ValueOf() 返回的 valueOfA 持有变量 a 的地址。

第 17 行中,使用 reflect.Value 类型的 Elem() 方法获取 a 地址的元素,也就是 a 的值。reflect.Value 的 Elem() 方法返回的值类型也是 reflect.Value。

第 20 行,此时 rValue 表示的是 a 的值且可以寻址。使用 SetInt() 方法设置值时不再发生崩溃。

第 23 行,正确打印修改的值。

提示

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/98792baee2e8e1e9e62ecdf5d74bb646.html