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

一、常见可能其实是在利用接口提取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