golang 反射reflect.MakeSlice 无法寻址问题

golang 反射reflect.MakeSlice 无法寻址问题

https://stackoverflow.com/questions/25384640/why-golang-reflect-makeslice-returns-un-addressable-value

一、常见可能其实是在利用接口提取relect生成的slice值中,忘记将接口转为slice。 go语言中存储在接口的值无法寻址。


type My struct {
	Name string
	Id   int
}

func main() {
    my := &My{}
    myType := reflect.TypeOf(my)
    slice := reflect.MakeSlice(reflect.SliceOf(myType), 10, 10).Interface()
	以下编译不通过,slice[0] (type interface{} does not support indexing
	//slice[0]=&My{“Foo“”,1} 
	或者
	//slice = slice.([]*My) //slice依然是interface{}
    //slice[0]=&My{"Foo",1}  //不可以
    
    //**解决方法:必须将接口转为slice,才可以使用
    p := slice.([]*My)
    p[0]=&My{"Foo",1}  //可以

    fmt.Println(slice)
    fmt.Printf("%T %d %d\n", p, len(p), cap(p))
}

二、链接上的问题,利用reflect.New()创建指针解决
其实我觉得下面的描述更直观。此时会报panic: reflect: reflect.flag.mustBeAssignable using unaddressable value,因为此时数组不可寻址。

func main() {
	my := &My{}
	myType := reflect.TypeOf(my)
	arr:=reflect.Zero(reflect.ArrayOf(10,myType))
	a:=&My{"Foo",1}
	arr.Index(1).Set(reflect.ValueOf(a))
	//panic: reflect: reflect.flag.mustBeAssignable using unaddressable value
	fmt.Println("arr[1]是否可寻址",arr.Index(1).CanAddr()) //false
	fmt.Println("arr[1]是否可Set",arr.Index(1).CanSet())	//false
}

利用reflect.New()创建指针解决,变成可寻址数组:

	prt:=reflect.New(arr.Type())
	prt.Elem().Set(arr)
	prt.Elem().Index(1).Set(reflect.ValueOf(a))
	fmt.Println("arr[1]是否可以寻址",prt.Elem().Index(1).CanAddr()) //true
	fmt.Println("arr[1]是否可以SET",prt.Elem().Index(1).CanSet())	//true
	fmt.Println("arr:",prt.Elem().Interface())	//arr: [<nil> 0xc0000a2500 <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil>]

如有理解不对,望指出,谢谢~


为什么 reflect.MakeSlice 返回一个不可寻址的Value?

在Go中,可寻址性的一个宽松定义是,你可以获取某个东西的地址,并确保这个地址指向某个有意义的地方。如果在函数体的栈上分配了某些内容,被分配的值的地址在某个时间节点将不再可访问。因此,该值不可寻址。在大多数情况下,如果本地栈变量被返回或以其他方式提升到外部,Go会将它们移动到堆中,但在运行时不会这样做( but at runtime this is not done)。因此,CanAddr()仅在以下情况下返回true:

A value is addressable if it is an element of a slice, an element of an addressable array, a field of an addressable struct, or the result of dereferencing a pointer.

如果值是切片的元素、可寻址数组的元素、可寻址结构体的字段或解引用的指针结果,则该值是可寻址的。

声明的类型都有一个共同点:它们保证它们所持有的东西可以从任何地方访问,并且指向内存中有意义的值。由于您使用reflect.MakeSlice创建了本地切片,所以您既没有切片元素,也没有指针,也没有任何其他提到的内容。但是,该切片的元素是可寻址的(因为该切片的内存保留在堆上)。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值