理解 reflect elem 和 value 的一段测试代码
发布于: 2021 年 03 月 31 日
问题一:为什么 mapValue.CanSet()是 false,却可以调用 SetMapIndex
fmt.Printf("mapValue CanSet:%t\n", mapValue.CanSet())    // mapValue CanSet:falsemapValue.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 加入
还未添加个人简介











 
    
评论