在Golang中为什么存储在接口中的值不可寻址 [英] Why value stored in an interface is not addressable in Golang

查看:506
本文介绍了在Golang中为什么存储在接口中的值不可寻址的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

引用golang维基( https://github.com/golang/go/ wiki / MethodSets#interfaces ):

存储在接口中的具体值不可寻址,同样,地图元素不可寻址。



映射值不可寻址的问题在这里解释:
为什么地图值不可寻址?



然而,关于界面并不清楚。他们为什么不可寻址?这是因为一些硬设计假设?

解决方案

为什么在接口中不存储非指针值可寻址?这是一个很好的问题,答案解释了为什么包含非​​指针值的接口不能成为带有指针接收器的方法的接收者,导致了可怕的错误:

 < type>没有实现< interface> (< name>方法有指针接收器)

tl; dr



存储在接口中的非指针值不可用于维护类型完整性。例如,在接口中指向 A 值的指向 A 当不同类型的 B 的值随后存储在界面中时将失效。由于存储在接口中的非指针值是不可寻址的,因此编译器无法将其地址传递给具有指针接收器的方法。



长答案

我在网上看到的答案没有多大意义。例如,这篇文章说:


原因是接口中的值位于隐藏内存
位置,因此编译器不能自动获得指向$ b的指针$ b为你记忆(用Go语言来说,这就是所谓的不是
可寻址)。


确实存储在接口中的值不可寻址,但据我所见,这不是因为它存储在隐藏的内存位置中。

另一个常见的答案是:

lockquote

创建接口值时,包含在界面中的值将被复制。因此不可能采用它的地址,即使你这样做,使用指向接口值的指针也会产生意想不到的效果(即无法更改原始复制值)。

这是没有意义的,因为指向复制到接口的值的指针与复制到指向值的指针没有区别一个具体类型;在这两种情况下,您都无法通过指向副本的指针更改原始复制值。

那么,为什么接口中存储的值不是可寻址的呢?答案在于后续的含义,如果它是可寻址的。



假设您有一个接口 I 和两种类型,即 A B

  type I interface {} 
type A int
type B string

创建 A 并将其存储在

  func main(){
var a A = 5
var i I = a
fmt.Printf(我是%T \ n,i)

假设我们可以获取存储在接口中的值的地址:
$ b $ pre $ var $ aPtr * A
aPtr =&(i。(A))//不允许,但如果是...

现在创建一个 B 并将其存储在 i 中:

  var b B =hello
i = b
fmt.Printf(我是%T型,aPtr是%T \ n型,i,aPtr)
}

以下是输出:

  i是main.A类型
i是main.B类型,aPtr是* main.A

B 分成 i 什么是 aPtr 指向? a ,但 t / strong>现在包含 B aPtr 不再是指向



然而,这是允许的:

 (A)
aPtr =& a2

由于第二行复制了 i。(A) aPtr中的值 不指向 i。(A)

无法将包含非指针值的接口作为具有指针接收器的方法的接收者?由于存储在接口中的非指针值不可寻址,因此编译器无法将其地址传递给具有指针接收器的方法。


Citing the golang wiki (https://github.com/golang/go/wiki/MethodSets#interfaces):

"The concrete value stored in an interface is not addressable, in the same way, that a map element is not addressable."

The question of map values not being addressable is explained here: Why are map values not addressable?

However, it is not clear regarding the interface. Why are they not addressable? Is this because of some hard design assumption?

解决方案

Why isn't a non-pointer value stored in an interface addressable? This is an excellent question, and the answer explains why an interface containing a non-pointer value can't be the receiver for a method with a pointer receiver, leading to the dreaded error:

<type> does not implement <interface> (<name> method has pointer receiver)

tl;dr

A non-pointer value stored in an interface isn't addressable to maintain type integrity. For example, a pointer to A, which points to a value of type A in an interface, would be invalidated when a value of a different type B is subsequently stored in the interface.

Because a non-pointer value stored in an interface isn't addressable, the compiler can't pass its address to a method with a pointer receiver.

Long answer

The answers I've seen online don't make much sense. For instance, this article says:

The reason is that the value in an interface is in a hidden memory location, and so the compiler can’t automatically get a pointer to that memory for you (in Go parlance, this is known as being "not addressable").

It's true that the value stored in an interface is not addressable, but as far as I can see it's not because its stored in "a hidden memory location".

Another common answer is:

When an interface value is created, the value that is wrapped in the interface is copied. It is therefore not possible to take its address, and even if you did, using a pointer to the interface value would have unexpected effects (ie. unable to alter the original copied value).

This makes no sense, since a pointer to a value copied into an interface would be no different than a pointer to a value copied into a concrete type; in both cases you can't alter the original copied value through the pointer to the copy.

So why isn't a value stored in an interface addressable? The answer lies in the follow-on implications if it were addressable.

Let's say you have an interface, I, and two types, A and B, which satisfy that interface:

type I interface{}
type A int
type B string

Create an A and store it in an I:

func main() {
    var a A = 5
    var i I = a
    fmt.Printf("i is of type %T\n", i)

Let's pretend we could take the address of a value stored in an interface:

    var aPtr *A
    aPtr = &(i.(A)) // not allowed, but if it were...

Now create a B and store it in i:

    var b B = "hello"
    i = b
    fmt.Printf("i is of type %T, aPtr is of type %T\n", i, aPtr)
}

Here's the output:

i is of type main.A
i is of type main.B, aPtr is of type *main.A

After putting a B into i, what is aPtr pointing to? aPtr was declared as pointing to an A, but t now contains a B, and aPtr is no longer a valid pointer to A.

This, however is permitted:

    var aPtr *A
    var a2 A = i.(A)
    aPtr = &a2

Because the second line makes a copy of the value in i.(A), and aPtr does not point to i.(A).

So, why can't an interface containing a non-pointer value be the receiver for a method with a pointer receiver? Because a non-pointer value stored in an interface isn't addressable, so the compiler can't pass its address to a method with a pointer receiver.

这篇关于在Golang中为什么存储在接口中的值不可寻址的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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