2013-03-20 85 views
4

如何获取接口内的值的地址?获取接口内的值地址

我存储在一个接口的结构,在list.List元素:

import "container/list" 
type retry struct{} 
p := &el.Value.(retry) 

但我得到这个:

cannot take the address of el.Value.(retry) 

这是怎么回事?由于结构存储在接口中,为什么我不能得到指向它的指针?

回答

5

要理解为什么这是不可能的,它有助于思考什么接口可变实际盟友是。一个接口值占用两个单词,第一个描述所包含值的类型,第二个(a)保存所包含的值(如果它适合在单词中)或(b)指向存储的指针(如果该值不符合一个词)。

要注意的重要事项是(1)包含的值属于接口变量,(2)当为变量分配新值时,可以重新使用该值的存储。知道了,考虑下面的代码:

var v interface{} 
v = int(42) 
p := GetPointerToInterfaceValue(&v) // a pointer to an integer holding 42 
v = &SomeStruct{...} 

现在的整数存储已经被重复使用,以容纳一个指针,而现在*p是指针的整数表示。你可以看到这是如何破坏类型系统的,因此Go没有提供这样做的方法(使用unsafe包之外)。

如果您需要一个指向您存储在列表中的结构体的指针,那么一个选项将存储指向列表中的结构体的指针,而不是直接存储结构体的值。或者,您可以将*list.Element值作为引用传递给包含的结构。

+0

这似乎更合理。我认为这足以说明你无法对所含价值的存储做出任何保证就足够了。 – 2013-03-22 07:34:25

+0

第二个想法是,我没有看到任何情况下可以调整接口存储与接口的大小,而无需重新定位接口。 – 2013-03-24 11:13:33

+0

好吧,我给出了一个用于接口值重用的存储的例子。由于该语言不能保证存储不会被重用,因此不要给你一个指向该存储的类型指针。由于接口值将更大的值存储在单独分配的内存中(使用第二个字作为指向该存储的指针),您将通过在您的列表中存储'* retry'值来使用相同数量的内存。 – 2013-03-26 06:54:26

2

第一个近似值:你不能那样做。即使你可以,p本身必须有interface{}类型,并不会太有用 - 你不能直接解引用它。

强制性问题是:你想解决什么问题?

最后但并非最不重要的:接口定义行为不结构。通常直接使用接口的底层实现类型会破坏接口契约,尽管可能存在非一般的合法情况。但是这些已经为type switch statement提供了一个静态已知类型的有限集合。

+0

我不明白为什么这是必要的。在类型声明之后,我应该能够获取由相应接口返回的右值引用所指向的值的地址。 – 2013-03-20 14:09:46

+1

@MattJoiner:如果接口中包含的值不是指针类型,则类型断言提供一个副本。但是你的问题题为:_“在地址__inside__一个界面_”。 (强调我的)。 IOW,如果你想要一个指向原来的非指针类型的指针,那么输入assertion将不会起作用,因为接口在内部只携带一个指向这个实例的指针(模数值适合机器字)。你为什么不直接在界面中放置一个指向值的指针?然后你用语言支持的方式直接获得你的想法。 – zzzz 2013-03-20 14:50:42

2

类型断言是导致两个值的表达式。在这种情况下的地址是不明确的。

p, ok := el.Value.(retry) 
if ok { 
    // type assertion successful 
    // now we can take the address 
    q := &p 
} 

从评论:

注意,这是一个指向指针的值的副本,而不是本身的价值。

James Henstridge

的解决问题的办法是简单因此;在界面中存储一个指针,而不是一个值。

+2

请注意,这是一个指向该值的副本的指针,而不是指向该值本身的指针。 – 2013-03-20 11:58:50

+0

这是不合理的。当然,我将它赋值为自动变量'p'后有一个副本。但虽然它仍然是一个右值,我应该能够获取该值存储在界面中的值的地址。由于接口以内嵌方式存储在'Value'中,因此假设接口_中的值是堆分配的,因此可以在适当的位置进行修改。 – 2013-03-20 14:12:50

+2

@MattJoiner:接口包含的大值实际上是堆分配的。但是指向该值的指针是一个非指定的,未公开的实现细节(关于语言本身以及我不能推荐使用的模数技术)。如果你需要一个接口的指针,那么在接口中放一个指针_into_。 – zzzz 2013-03-20 14:57:12

2

Get pointer to interface value?

有没有一种方法,给定的接口类型的变量,得到一个 指向存储在变量中的值吗?

这是不可能的。

罗布派克

接口值不一定寻址的。例如,

package main 

import "fmt" 

func main() { 
    var i interface{} 
    i = 42 
    // cannot take the address of i.(int) 
    j := &i.(int) 
    fmt.Println(i, j) 
} 

Address operators

对于类型T的操作数X,写入动作& X生成 指针类型* T的至x。操作数必须是可寻址的,即 变量,指针间接或片索引操作; 或可寻址结构操作数的字段选择器;或者可寻址阵列的索引操作的数组 。作为 可寻址性要求的例外,x也可以是复合文字。

参考文献:

Interface types

Type assertions

Go Data Structures: Interfaces

Go Interfaces