正文
reflect.ValueOfreflect.TypeOf
Elem()reflect.ValueOfElem()reflect.ValueOf
那我们什么时候应该传递指针参数呢?
什么时候传递指针?
要回答这个问题,我们可以思考一下以下列出的几点内容:
chanmapsliceinterfaceTypeOfValueOfinterfaceinterfacev := reflect.ValueOf(&a)v.CanSet()falsev.Elem().CanSet()true
chanmapslice
1. 通过传递指针修改变量的值
panic
传值无法修改变量本身
vxxpanic
传指针可以修改变量
xreflect.ValueOfvxvx
2. 通过传递指针修改结构体的字段
reflect.ValueOfpanic
3. 结构体:获取指针接收值方法
对于结构体而言,如果我们想通过反射来调用指针接收者方法,那么我们需要传递指针。
在开始讲解这一点之前,需要就以下内容达成共识:
pM1&pM1M2pM2p&pM2
但是在反射的时候,我们是无法做到这一点的,这个需要特别注意。如果我们想通过反射来调用指针接收者的方法,就需要传递指针。
4. 变量本身包含指向数据的指针
最好不要通过值的反射对象来修改值的数据,就算有些类型可以实现这种功能。
chanmapslicereflect.ValueOf
通过值反射对象修改 chan、map 和 slice
chanmapsliceunsafe.Pointer
chanmapslice
slice 反射对象扩容的影响
mapslicemapslicemapslice
sliceslicearraysliceslicemapslicemap
示例代码:
v5v4arraysarrayv5s
虽然通过值反射对象可以修改 slice 的数据,但是如果通过反射对象 append 元素到 slice 的反射对象的时候, 可能会触发 slice 扩容,这个时候再修改反射对象的时候,就影响不了原来的 slice 了。
slice 容量够的话是不是就可以正常追加元素了?
只能说,能,也不能。我们看看下面这个例子:
slices1s1lens1
len
slice[0, len(s))
map 也不能通过值反射对象来修改其元素。
slicemap
但是,从另一个角度看,如果我们只是修改其元素的话,是可以正常修改的。
chan 没有追加
chanslicemapchan
chanch&chreflect.ValueOfch
结构体字段包含指针的情况
reflect.ValueOf
p&pNameNamepName
p
5. interface 类型处理
interface
我们可以通过下面的断言来证明:
当然,对于指针类型也是一样的:
同样的,我们可以通过下面的断言来证明:
interface 底层类型是值
interfacereflect.ValueOfinterface
v := reflect.ValueOf(i)v := reflect.ValueOf(p)reflect.ValueOf(p)pinterface{}ipinterface{}reflect.ValueOf
interface 底层类型是指针
interfacereflect.ValueOfinterfacereflect.ValueOf
不要再对接口类型取地址
能不能通过反射 Value 对象来修改变量只取决于,能不能根据反射对象拿到最初变量的内存地址。 如果拿到的只是原始值的拷贝,不管我们怎么做都无法修改原始值。
对于初学者另外一个令人困惑的地方可能是下面这样的代码:
reflect.ValueOf()interface{}
reflectreflect.ValueOf()
v2interface{}a
aai
iaaiv2
上图说明:
iaint&iefacev2efacev2iia
aa
6. 指针类型反射对象不可修改其指向地址
其实这一点上面有些地方也有涉及到,但是这里再强调一下。一个例子如下:
说明:
v&aElem()aElem()
Elem()
7. 反射也不能修改字符串中的字符
String
在 go 中,字符串是用一个结构体来表示的,大概长下面这个样子:
DataLen
str[1] = 'a'
相同的字符串只有一个实例
假设我们定义了两个相同的字符串,如下:
s1s2hello
两个字符串内存表示如下:
s1s2
字符串本身可以替换
虽然我们不能修改字符串中的某一个字符,但是我们可以通过反射对象把整个字符串替换掉:
sworldhelloworld
这可以用下图表示:
总结
reflect.ValueOf()chanmapslicereflect.ValueOf()mapslicemapsliceinterfaceinterfaceinterfaceinterfacestirng
但其实说了那么多,简单来说只有一点,就是我们只能通过反射对象来修改指针类型的变量。如果拿不到实际存储数据的指针,那么我们就无法通过反射对象来修改其中的元素了。