理解 reflect elem 和 value 的一段测试代码
发布于: 2021 年 03 月 31 日
问题一:为什么 mapValue.CanSet()是 false,却可以调用 SetMapIndex
fmt.Printf("mapValue CanSet:%t\n", mapValue.CanSet()) // mapValue CanSet:false
mapValue.SetMapIndex(reflect.ValueOf("height"), reflect.ValueOf(60))
复制代码
map 和 slice 本身就是指针,当 reflect.ValueOf(m)而不是 reflect.ValueOf(&m),map 指针本身是不能修改改,也就是你不能修改 map 指向的内存地址,mapValue.CanSet()返回 false,但是内存地址里面的数据却是可以修改的 mapValue.SetMapIndex(reflect.ValueOf("height"), reflect.ValueOf(60)。这个对 C 语言指针有了解的肯定能很好理解。如下面的 c 语言代码,p 是 const 指针本身不能修改,不能再指向 b 了,但是却可以改变 a 的数值。
#include <stdio.h>
int main()
{
int a = 12;
int b = 22;
int* const p = &a;
//会报错:assignment of read-only variable 'p'
//因为p指针是const的,已经是p指向a,就不能让p再指向其他地方了
//p = &b;
//不报错,因为不能修改p指针,但是可以修改p指向的内存数据,比如这里的a
*p = 98;
//输出98
printf("%d \n", a);
return 0;
}
复制代码
问题二:为什么为什么修改 m 也相当于修改了 om?
这个问题跟问题一是差不多的,如果还是没理解就先去搞懂 c 语言的指针。
map 和 slice 本身就是指针,如果修改 &map 实际上是修改了 map 指针指向的内存,
mapPtrValue.Elem().Set(reflect.ValueOf(om))
实际上是使 m 和 om 都指向了同一块内存,也就是 om 原先指向的那个内存,所以当修改 m 的时候,实际修改的是 m 指向的内存里的数据,所以 om 里面的数据也改变了。
同理可以看[]int 是一样的。
package main
import (
"fmt"
"reflect"
)
type Blog struct {
ID int
Name string `gorm:"embedded;embeddedPrefix:author_"`
Upvotes int32
}
func main() {
var i int
intValue := reflect.ValueOf(i)
fmt.Printf("intValue value:%v\n", intValue) // intValue value:0
fmt.Printf("intValue type:%v\n", intValue.Type()) // intValue type:int
fmt.Printf("intValue kind:%v\n", intValue.Type().Kind()) // intValue kind:int
reflect.ValueOf(intValue)
fmt.Printf("intValue CanSet:%t\n\n", intValue.CanSet()) // intValue CanSet:false
intPtrValue := reflect.ValueOf(&i)
fmt.Printf("intPtrValue value:%v\n", intPtrValue) // intPtrValue value:0xc0000120a0
fmt.Printf("intPtrValue type:%v\n", intPtrValue.Type()) // intPtrValue type:*int
fmt.Printf("intPtrValue kind:%v\n", intPtrValue.Type().Kind()) // intPtrValue kind:ptr
fmt.Printf("intPtrValue CanSet:%t\n", intPtrValue.CanSet()) // intPtrValue CanSet:false
fmt.Printf("intPtrValue Elem CanSet:%t\n", intPtrValue.Elem().CanSet()) // intPtrValue Elem CanSet:true
fmt.Printf("intPtrValue Indirect CanSet:%t\n", reflect.Indirect(intPtrValue).CanSet()) // intPtrValue Indirect CanSet:true
intPtrValue.Elem().SetInt(123)
fmt.Printf("intPtrValue Elem SetInt:%v\n", i) // intPtrValue Elem SetInt:123
reflect.Indirect(intPtrValue).SetInt(245)
fmt.Printf("intPtrValue Indirect SetInt:%v\n\n", i) // intPtrValue Indirect SetInt:245
var str string
strValue := reflect.ValueOf(str)
fmt.Printf("strVal value:%v\n", strValue) // strVal value:
fmt.Printf("strVal type:%v\n", strValue.Type()) // strVal type:string
fmt.Printf("strVal kind:%v\n", strValue.Type().Kind()) // strVal kind:string
fmt.Printf("strValue CanSet:%t\n", strValue.CanSet()) // strValue CanSet:false
strPtrValue := reflect.ValueOf(&str)
fmt.Printf("strPtrValue value:%v\n", strPtrValue) // strPtrValue value:0xc0000341f0
fmt.Printf("strPtrValue type:%v\n", strPtrValue.Type()) // strPtrValue type:*string
fmt.Printf("strPtrValue kind:%v\n", strPtrValue.Type().Kind()) // strPtrValue kind:ptr
fmt.Printf("strPtrValue CanSet:%t\n", strPtrValue.CanSet()) // strPtrValue CanSet:false
fmt.Printf("strPtrValue Elem CanSet:%t\n", strPtrValue.Elem().CanSet()) // strPtrValue Elem CanSet:true
fmt.Printf("strPtrValue Indirect CanSet:%t\n", reflect.Indirect(strPtrValue).CanSet()) // strPtrValue Indirect CanSet:true
strPtrValue.Elem().SetString("abc")
fmt.Printf("strPtrValue Elem SetString:%v\n", str) // strPtrValue Elem SetString:abc
reflect.Indirect(strPtrValue).SetString("efg")
fmt.Printf("strPtrValue Indirect SetString:%v\n\n", str) // strPtrValue Indirect SetString:efg
var blog Blog
structValue := reflect.ValueOf(blog)
fmt.Printf("structValue value:%v\n", structValue) // structValue value:{0 0}
fmt.Printf("structValue type:%v\n", structValue.Type()) // structValue type:main.Blog
fmt.Printf("structValue kind:%v\n", structValue.Type().Kind()) // structValue kind:struct
fmt.Printf("structValue CanSet:%t\n", structValue.CanSet()) // structValue CanSet:false
structPtrValue := reflect.ValueOf(&blog)
fmt.Printf("structPtrValue value:%v\n", structPtrValue) // structPtrValue value:&{0 0}
fmt.Printf("structPtrValue type:%v\n", structPtrValue.Type()) // structPtrValue type:*main.Blog
fmt.Printf("structPtrValue kind:%v\n", structPtrValue.Type().Kind()) // structPtrValue kind:ptr
fmt.Printf("structPtrValue CanSet:%t\n", structPtrValue.CanSet()) // structPtrValue CanSet:false
fmt.Printf("structPtrValue Elem CanSet:%t\n", structPtrValue.Elem().CanSet()) // structPtrValue Elem CanSet:true
bbb := Blog{
Name: "sdga",
}
structPtrValue.Elem().Set(reflect.ValueOf(bbb))
fmt.Printf("structPtrValue Set:%+v\n\n", blog) // structPtrValue Set:{ID:0 Name:sdga Upvotes:0}
m := map[string]interface{}{
"class": "class1",
}
fmt.Printf("m addr:%p\n", &m)
mapValue := reflect.ValueOf(m)
fmt.Printf("mapValue value:%v\n", mapValue) // mapValue value:map[class:class1]
fmt.Printf("mapValue type:%v\n", mapValue.Type()) // mapValue type:map[string]interface {}
fmt.Printf("mapValue kind:%v\n", mapValue.Type().Kind()) // mapValue kind:map
fmt.Printf("mapValue CanSet:%t\n", mapValue.CanSet()) // mapValue CanSet:false
mapValue.SetMapIndex(reflect.ValueOf("height"), reflect.ValueOf(60))
mapPtrValue := reflect.ValueOf(&m)
fmt.Printf("mapPtrValue value:%+v\n", mapPtrValue) // mapPtrValue value:&map[class:class1 height:60]
fmt.Printf("mapPtrValue type:%v\n", mapPtrValue.Type()) // mapPtrValue type:*map[string]interface {}
fmt.Printf("mapPtrValue kind:%v\n", mapPtrValue.Type().Kind()) // mapPtrValue kind:ptr
fmt.Printf("mapPtrValue CanSet:%t\n", mapPtrValue.CanSet()) // mapPtrValue CanSet:false
fmt.Printf("mapPtrValue Elem CanSet:%t\n", mapPtrValue.Elem().CanSet()) // mapPtrValue Elem CanSet:true
om := map[string]interface{}{
"name": "werben",
"age": 16,
}
mapPtrValue.Elem().SetMapIndex(reflect.ValueOf("class"), reflect.ValueOf("1"))
fmt.Printf("om addr:%p\n", &om)
mapPtrValue.Elem().Set(reflect.ValueOf(om))
mapPtrValue.Elem().SetMapIndex(reflect.ValueOf("addr"), reflect.ValueOf("sz"))
fmt.Printf("mapPtrValue Set:%+v\n", m) // mapPtrValue Set:map[addr:sz age:16 name:werben]
fmt.Printf("mapPtrValue om:%+v\n\n", om) // mapPtrValue om:map[addr:sz age:16 name:werben]
fmt.Printf("m addr:%p, %p\n", &m, m) // m addr:0xc000086000, 0xc0000880f0
fmt.Printf("om addr:%p, %p\n", &om, om) // om addr:0xc000086008, 0xc0000880f0
m["avatar"] = "aaaaaaaa"
om["sex"] = "girl"
fmt.Printf("mapPtrValue Set:%+v\n", m) // mapPtrValue Set:map[addr:sz age:16 avatar:aaaaaaaa name:werben sex:girl]
fmt.Printf("mapPtrValue om:%+v\n\n", om) // mapPtrValue om:map[addr:sz age:16 avatar:aaaaaaaa name:werben sex:girl]
arr := []int{1, 2, 3, 4, 5}
arrValue := reflect.ValueOf(arr)
fmt.Printf("arrValue value:%v\n", arrValue) // arrValue value:[1 2 3 4 5]
fmt.Printf("arrValue type:%v\n", arrValue.Type()) // arrValue type:[]int
fmt.Printf("arrValue kind:%v\n", arrValue.Type().Kind()) // arrValue kind:slice
fmt.Printf("arrValue CanSet:%t\n", arrValue.CanSet()) // arrValue CanSet:false
arrValue.Index(1).SetInt(123)
arrPtrValue := reflect.ValueOf(&arr)
fmt.Printf("arrPtrValue value:%+v\n", arrPtrValue) // arrPtrValue value:&[1 123 3 4 5]
fmt.Printf("arrPtrValue type:%v\n", arrPtrValue.Type()) // arrPtrValue type:*[]int
fmt.Printf("arrPtrValue kind:%v\n", arrPtrValue.Type().Kind()) // arrPtrValue kind:ptr
fmt.Printf("arrPtrValue CanSet:%t\n", arrPtrValue.CanSet()) // arrPtrValue CanSet:false
fmt.Printf("arrPtrValue Elem CanSet:%t\n", arrPtrValue.Elem().CanSet()) // arrPtrValue Elem CanSet:true
orr := []int{6, 7, 8, 9, 10}
arrPtrValue.Elem().Index(1).SetInt(555)
fmt.Printf("arr addr:%p, %p\n", &arr, arr) // arr addr:0xc000086140, 0xc0000920c0
arrPtrValue.Elem().Set(reflect.ValueOf(orr))
arrPtrValue.Elem().Index(1).SetInt(666)
fmt.Printf("arrPtrValue Set:%+v\n", arr) // arrPtrValue Set:[6 666 8 9 10]
fmt.Printf("arrPtrValue om:%+v\n", orr) // arrPtrValue om:[6 666 8 9 10]
fmt.Printf("arr addr:%p, %p\n", &arr, arr) // arr addr:0xc00008e140, 0xc00008c210
fmt.Printf("orr addr:%p, %p\n\n", &orr, orr) // orr addr:0xc00008e1e0, 0xc00008c210
}
复制代码
划线
评论
复制
发布于: 2021 年 03 月 31 日阅读数: 13
版权声明: 本文为 InfoQ 作者【werben】的原创文章。
原文链接:【http://xie.infoq.cn/article/09c3cfe6918c938d266af2182】。文章转载请联系作者。
werben
关注
还未添加个人签名 2018.01.08 加入
还未添加个人简介
评论