获取接口内值的地址

huangapple go评论143阅读模式
英文:

Take address of value inside an interface

问题

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

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

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

但是我得到了这个错误:

无法获取el.Value.(retry)的地址

发生了什么?既然结构体存储在接口中,为什么我不能获取它的指针?

英文:

How do I take the address of a value inside an interface?

I have an struct stored in an interface, in a list.List element:

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

But I get this:

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

What's going on? Since the struct is stored in the interface, why can't I get a pointer to it?

答案1

得分: 10

要理解为什么这是不可能的,有助于思考接口变量实际上是什么。接口值占用两个字,第一个描述包含值的类型,第二个要么(a)保存包含的值(如果它适合一个字),要么(b)保存值的存储的指针(如果值不适合一个字)。

需要注意的重要事项是(1)包含的值属于接口变量,(2)当新值被赋给变量时,该值的存储可能被重用。了解了这一点,考虑以下代码:

var v interface{}
v = int(42)
p := GetPointerToInterfaceValue(&v) // 指向保存42的整数的指针
v = &SomeStruct{...}

现在整数的存储已被重用以保存一个指针,*p 现在是该指针的整数表示。你可以看到这有可能破坏类型系统,所以Go语言没有提供一种方法来做到这一点(除非使用unsafe包)。

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

英文:

To understand why this isn't possible, it is helpful to think about what an interface variable actually is. An interface value takes up two words, with the first describing the type of the contained value, and the second either (a) holding the contained value (if it fits within the word) or (b) a pointer to storage for the value (if the value does not fit within a word).

The important things to note are that (1) the contained value belongs to the interface variable, and (2) the storage for that value may be reused when a new value is assigned to the variable. Knowing that, consider the following code:

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

Now the storage for the integer has been reused to hold a pointer, and *p is now an integer representation of that pointer. You can see how this has the capacity to break the type system, so Go doesn't provide a way to do this (outside of using the unsafe package).

If you need a pointer to the structs you're storing in a list, then one option would be to store pointers to the structs in the list rather than struct values directly. Alternatively, you could pass *list.Element values as references to the contained structures.

答案2

得分: 2

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

英文:

A type assertion is an expression that results in two values. Taking the address in this case would be ambiguous.

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

From the comments:

>Note that this is a pointer to a copy of the value rather than a pointer to the value itself.
>
>— James Henstridge

The solution to the problem is therefore simple; store a pointer in the interface, not a value.

答案3

得分: 2

给定一个接口类型的变量,是否有办法获取存储在变量中的值的指针?

不可能。

Rob Pike

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

package main

import "fmt"

func main() {
    var i interface{}
    i = 42
    // 无法获取 i.(int) 的地址
    j := &i.(int)
    fmt.Println(i, j)
}

地址操作符

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

参考资料:

接口类型

类型断言

Go数据结构:接口

Go接口

英文:

> Get pointer to interface value?
>
> Is there a way, given a variable of interface type, of getting a
> pointer to the value stored in the variable?
>
> It is not possible.
>
> Rob Pike

Interface values are not necessarily addressable. For example,

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
>
> For an operand x of type T, the address operation &x generates a
> pointer of type *T to x. The operand must be addressable, that is,
> either a variable, pointer indirection, or slice indexing operation;
> or a field selector of an addressable struct operand; or an array
> indexing operation of an addressable array. As an exception to the
> addressability requirement, x may also be a composite literal.

References:

Interface types

Type assertions

Go Data Structures: Interfaces

Go Interfaces

答案4

得分: 1

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

必须问的问题是:你试图解决什么问题?

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

英文:

In the first approximation: You cannot do that. Even if you could, p itself would the have to have type interface{} and would not be too helpful - you cannot directly dereference it then.

The obligatory question is: What problem are you trying to solve?

And last but not least: Interfaces define behavior not structure. Using the interface's underlying implementing type directly in general breaks the interface contract, although there might be non general legitimate cases for it. But those are already served, for a finite set of statically known types, by the type switch statement.

huangapple
  • 本文由 发表于 2013年3月20日 16:50:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/15518919.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定