CanSet, CanAddr是什么

  介绍

这篇文章主要介绍了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的指针。这点往往是需要我们注意的。

CanSet, CanAddr是什么