这篇文章主要介绍了CanSet, CanAddr是什么,具有一定借鉴价值,需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获。下面让小编带着大家一起了解一下。
<强>一篇理解什么是CanSet, CanAddr ? 强>
<强>什么是可设置(CanSet) 强>
首先需要先明确下,可设置是针对反映。值的。普通的变量要转变成为反映。值需要先使用reflect.ValueOf()来进行转化。
那么为什么要有这么一个“可设置”的方法呢?比如下面这个例子:
x float64=3.4 v var:=reflect.ValueOf (x) fmt.Println (v.CanSet())//假
golang里面的所有函数调用都是值复制,所以这里在调用反映。返回对象的值的时候,已经复制了一个x传递进去了,这里获取到的v是一个x复制体的价值。那么这个时候,我们就希望知道我能不能通过v来设置这里的x变量。就需要有个方法来辅助我们做这个事情:CanSet ()
但是,非常明显,由于我们传递的是x的一个复制,所以这里根本无法改变x的值。这里显示的就是假的。
那么如果我们把x的地址传递给里面呢?下面这个例子:
x float64=3.4 v var:=reflect.ValueOf (, x) fmt.Println (v.CanSet())//假
我们将x变量的地址传递给反映。返回对象的值了。应该是CanSet了吧。但是这里却要注意一点,这里的v指向的是x的指针。所以CanSet方法判断的是x的指针是否可以设置。指针是肯定不能设置的,所以这里还是返回错误的。
那么我们下面需要可以通过这个指针的价值值来判断的是,这个指针指向的元素是否可以设置,所幸反映提供了Elem()方法来获取这个”指针指向的元素”。
x float64=3.4 v var:=reflect.ValueOf (, x) fmt.Println (v.Elem () .CanSet())//真正的
终于返回真正的了。但是这个Elem()使用的时候有个前提,这里的值必须是指针对象转换的反映。价值。(或者是接口对象转换的反映。值)。这个前提不难理解吧,如果是一个int类型,它怎么可能有指向的元素呢?所以,使用Elem的时候要十分注意这点,因为如果不满足这个前提,Elem是直接触发恐慌的。
在判断完是否可以设置之后,我们就可以通过SetXX系列方法进行对应的设置了。
x float64=3.4 v var:=reflect.ValueOf (x),如果v.Elem () .CanSet () { v.Elem () .SetFloat (7.1)} fmt.Println (x)
<强>更复杂的类型强>
对于复杂的片,地图,结构、指针等方法,我写了一个例子:
包mainimport ( “fmt" “reflect") {Foo接口类型 名称()字符串}FooStruct struct类型{ 一个字符串}func (f FooStruct)名称字符串(){ 返回f。一种}FooPointer结构{ 一个字符串}func (f * FooPointer)名称字符串(){ 返回f。一个}函数main () { {//片 答:=int [] {1,2,3} 瓦尔:=reflect.ValueOf (,) .SetLen val.Elem () (2) val.Elem () .Index (0) .SetInt (4) fmt.Println (a)//(4,2) } {//地图 答:={地图(int)字符串 1:“foo1", 2:“foo2", } 瓦尔:=reflect.ValueOf (,) key3:=reflect.ValueOf (3) val3:=reflect.ValueOf (“foo3") val.Elem ()。SetMapIndex (key3 val3) fmt.Println (val)//和地图(1:foo1 2: foo2 3: foo3] } {//地图 答:={地图(int)字符串 1:“foo1", 2:“foo2", } 瓦尔:=reflect.ValueOf (a) key3:=reflect.ValueOf (3) val3:=reflect.ValueOf (“foo3") val.SetMapIndex (key3 val3) fmt.Println (val)//和地图(1:foo1 2: foo2 3: foo3] } {//结构体 答:=FooStruct {} 瓦尔:=reflect.ValueOf (,) val.Elem () .FieldByName (“A") .SetString (“foo2") fmt.Println (a)//{foo2} } {//指针 答:=,FooPointer {} 瓦尔:=reflect.ValueOf (a) val.Elem () .FieldByName (“A") .SetString (“foo2") fmt.Println (a)//, {foo2} }}
上面的例子如果都能理解,那基本上也就理解了CanSet的方法了。
特别可以关注下,地图,指针在修改的时候并不需要传递指针到体现。返回对象的值中。因为他们本身就是指针。
所以在调用反映。返回对象的值的时候,我们必须心里非常明确,我们要传递的变量的底层结构,比如地图,实际上传递的是一个指针,我们没有必要再将他指针化了,而片实际上传递的是一个SliceHeader结构,我们在修改片的时候,必须要传递的是SliceHeader的指针。这点往往是需要我们注意的。