7

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

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

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

但我明白了:

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

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

4

4 回答 4

9

要理解为什么这是不可能的,考虑一下接口变量实际上是什么是有帮助的。接口值占用两个字,第一个描述包含值的类型,第二个(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值作为对包含结构的引用传递。

于 2013-03-22T05:20:20.493 回答
2

在第一个近似值:你不能这样做。即使你可以,p它本身也必须有类型interface{}并且不会太有帮助 - 你不能直接取消引用它。

强制性问题是:您要解决什么问题?

最后但同样重要的是:接口定义行为而不是结构。直接使用接口的底层实现类型通常会破坏接口契约,尽管它可能存在非一般的合法情况。但是对于一组有限的静态已知类型,这些已经由类型 switch 语句提供。

于 2013-03-20T08:59:44.133 回答
2

类型断言是产生两个值的表达式。在这种情况下取​​地址将是模棱两可的。

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

从评论:

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

詹姆斯·亨斯特里奇

因此,问题的解决方案很简单;在接口中存储一个指针,而不是一个值。

于 2013-03-20T09:51:25.357 回答
2

获取指向接口值的指针?

给定接口类型的变量,有没有办法获取指向存储在变量中的值的指针?

这不可能。

罗布·派克

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

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)
}

地址运算符

对于 T 类型的操作数 x,地址操作 &x 生成 *T 类型的指向 x 的指针。操作数必须是可寻址的,即变量、指针间接或切片索引操作;或可寻址结构操作数的字段选择器;或可寻址数组的数组索引操作。作为可寻址性要求的一个例外,x 也可以是复合文字。

参考:

接口类型

类型断言

Go 数据结构:接口

转到接口

于 2013-03-20T14:49:49.613 回答