如何获取接口内的值的地址?
我有一个存储在接口中的结构,在 list.List 元素中:
import "container/list"
type retry struct{}
p := &el.Value.(retry)
但我明白了:
cannot take the address of el.Value.(retry)
这是怎么回事?既然结构体存储在接口中,为什么我不能得到指向它的指针呢?
如何获取接口内的值的地址?
我有一个存储在接口中的结构,在 list.List 元素中:
import "container/list"
type retry struct{}
p := &el.Value.(retry)
但我明白了:
cannot take the address of el.Value.(retry)
这是怎么回事?既然结构体存储在接口中,为什么我不能得到指向它的指针呢?
要理解为什么这是不可能的,考虑一下接口变量实际上是什么是有帮助的。接口值占用两个字,第一个描述包含值的类型,第二个(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
值作为对包含结构的引用传递。
在第一个近似值:你不能这样做。即使你可以,p
它本身也必须有类型interface{}
并且不会太有帮助 - 你不能直接取消引用它。
强制性问题是:您要解决什么问题?
最后但同样重要的是:接口定义行为而不是结构。直接使用接口的底层实现类型通常会破坏接口契约,尽管它可能存在非一般的合法情况。但是对于一组有限的静态已知类型,这些已经由类型 switch 语句提供。
类型断言是产生两个值的表达式。在这种情况下取地址将是模棱两可的。
p, ok := el.Value.(retry)
if ok {
// type assertion successful
// now we can take the address
q := &p
}
从评论:
请注意,这是指向值副本的指针,而不是指向值本身的指针。
因此,问题的解决方案很简单;在接口中存储一个指针,而不是一个值。
给定接口类型的变量,有没有办法获取指向存储在变量中的值的指针?
这不可能。
罗布·派克
接口值不一定是可寻址的。例如,
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 也可以是复合文字。
参考: