为什么golang反映.MakeSlice返回不可寻址的值 [英] Why golang reflect.MakeSlice returns un-addressable Value

查看:1019
本文介绍了为什么golang反映.MakeSlice返回不可寻址的值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请查看下面的代码段:



http:// play。 golang.org/p/xusdITxgT-



为什么会发生这种情况?因为我的一个论点必须是切片地址。



也许我没有向每个人讲清楚。



<$ (& result)

以上代码就是为什么我需要一个分片地址。



结果变量是我需要的。现在通常我可以做到这一点

  result:= make([] SomeStruct,10,10)

但是现在SomeStruct是动态的,我需要使用reflect.MakeSlice创建切片,所以

  result:= reflect.MakeSlice(reflect.SliceOf(SomeType))

它的错误:结果必须是分片地址。

解决方案

如何获取使用反射指向切片



最简单的解决方案可能是使用 reflect.New()来创建指针(完整示例):

 my:=& My {} 

//创建一个以
开头的分片myType:= reflect.TypeOf(my)
slice:= reflect.MakeSlice(reflect.SliceOf(myType),10,10)

//创建一个指向切片值的指针并将其设置为切片
x:= reflect。 New(slice.Type())
x.Elem()。Set(分片)

collection.Find(bson.M {})。All(x.Interface())

请注意其他答案指出的 x.Interface()。这样可以防止 reflect.Value 的实际值 x 的实际值传递给全部()

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



一个松散的可寻址性是您可以获取某些内容的地址,并确保该地址指向某个有意义的地方。如果您在函数体中的堆栈中分配了某些内容,那么分配的值​​的地址在某个时间点将不再可用。因此,这个值是不可寻址的。在大多数情况下,如果Go将本地堆栈变量返回或以其他方式提升到外部,那么Go会将本地堆栈变量移动到堆中,但在运行时不会执行此操作。因此, CanAddr() 在以下情况下只返回 true


如果值是切片,可寻址数组的元素,可寻址结构的字段或取消引用指针的结果。


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



为什么指向片的指针?



在这种情况下,我的主要问题是,为什么API的 mgo 需要一个指向 iter.All ?毕竟,切片是引用类型,对于提供的数据集的更改,不需要指针。但后来我发现,大部分时间功能 追加到切片。追加导致内存分配,内存分配导致将旧数据复制到新内存,新内存意味着需要将新地址传送给调用者。

这个行为在演示。本质上:

  // Works。使用切片的可用存储。 
resultv.Index(1).Set(a)

//执行但改变丢失:
// reflect.Append(resultv,a)

//无效:reflect.Value.Set使用不可寻址的值
// resultv.Set(reflect.Append(resultv,a))


check the Snippet below:

http://play.golang.org/p/xusdITxgT-

Why is this happening? Because one of my argument must be a slice address.

Maybe I did not made it clear for everyone.

collection.Find(bson.M{}).All(&result)

The above code is why I need a slice address.

the result variable here is what I need. Now usually I can do this

result := make([]SomeStruct, 10, 10)

But now the SomeStruct is dynamic and I need to create the slice by using reflect.MakeSlice, So

result := reflect.MakeSlice(reflect.SliceOf(SomeType))

And it errors on : result must be a slice address.

解决方案

How to get a pointer to a slice using reflection

The simplest solution is probably to use reflect.New() to create the pointer (full example on play):

my := &My{}

// Create a slice to begin with
myType := reflect.TypeOf(my)
slice := reflect.MakeSlice(reflect.SliceOf(myType), 10, 10)

// Create a pointer to a slice value and set it to the slice
x := reflect.New(slice.Type())
x.Elem().Set(slice)

collection.Find(bson.M{}).All(x.Interface())

Note the x.Interface() that was pointed out by other answers as well. This prevents that instead of the reflect.Value the actual value of x is passed to All().

Why does reflect.MakeSlice return an un-addressable Value?

A loose definition of addressability in Go is that you can take the address of something and are guaranteed that this address points to somewhere meaningful. If you allocate something on the stack in the body of a function, the address of the allocated value will, at some point in time, not be accessible anymore. Therefore, this value is not addressable. In most cases, Go moves local stack variables to the heap if they are returned or otherwise promoted to the outside, but at runtime this is not done. Therefore, CanAddr() returns only true when:

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.

The stated types all have one thing in common: they guarantee that what they hold will be accessible from everywhere and point to a meaningful value in memory. You have neither a slice element, nor a pointer, nor any of the other mentioned things since you created a local slice using reflect.MakeSlice. The elements of said slice would be addressable though (since the slice's memory resides on the heap).

Why a pointer to a slice?

The main question for me in this case was, why does the API of mgo require a pointer to a slice for iter.All? After all, slices are reference types and for changes in the provided data set, no pointer is necessary. But then it occurred to me that most of the time the function appends to the slice. Appending leads to memory allocation, memory allocation leads to copying the old data to new memory, new memory means a new address which needs to be communicated to the caller.

This behaviour is illustrated in this example on play. In essence:

// Works. Uses available storage of the slice.
    resultv.Index(1).Set(a)

// Executes but changes are lost:   
//  reflect.Append(resultv, a)

// Does not work: reflect.Value.Set using unaddressable value
//  resultv.Set(reflect.Append(resultv, a))

这篇关于为什么golang反映.MakeSlice返回不可寻址的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆