为什么存储在接口中的值在Golang中无法寻址

Lem*_*ata 6 go

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

"存储在接口中的具体值不可寻址,就像地图元素不可寻址一样."

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

但是,关于界面还不清楚.为什么他们无法解决?这是因为一些硬设计假设吗?

WPW*_*dJr 19

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

<type> does not implement <interface> (<name> method has pointer receiver)
Run Code Online (Sandbox Code Playgroud)

TL;博士

存储在接口中的非指针值不可寻址以维持类型完整性.例如,当接口中随后存储不同类型B的值时,指向A的指针(其指向接口中的类型A的值)将无效.

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

答案很长

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

原因是接口中的值位于隐藏的内存位置,因此编译器无法为您自动获取指向该内存的指针(在Go的说法中,这被称为"无法寻址").

存储在接口中的值确实是不可寻址的,但据我所知,并不是因为它存储在"隐藏的存储位置"中.

另一个常见的答案是:

创建接口值时,将复制包含在接口中的值.因此无法获取其地址,即使您这样做,使用指向接口值的指针也会产生意外影响(即无法更改原始复制值).

这是没有意义的,因为指向复制到接口中的值的指针与指向复制到具体类型的值的指针没有什么不同; 在这两种情况下,您都无法通过指向副本的指针更改原始复制值.

那么为什么存储在接口中的值不可寻址?答案在于如果它可解决的后续影响.

假设您有一个接口I,以及满足该接口的两种类型AB:

type I interface{}
type A int
type B string
Run Code Online (Sandbox Code Playgroud)

创建一个A并将其存储在I中:

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

让我们假装我们可以获取存储在接口中的值的地址:

    var aPtr *A
    aPtr = &(i.(A)) // not allowed, but if it were...
Run Code Online (Sandbox Code Playgroud)

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

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

这是输出:

i is of type main.A
i is of type main.B, aPtr is of type *main.A
Run Code Online (Sandbox Code Playgroud)

B放入i之后,aPtr指向什么? aPtr被声明为指向A,但是t现在包含一个B,而aPtr不再是指向A的有效指针.

但是,允许这样做:

    var aPtr *A
    var a2 A = i.(A)
    aPtr = &a2
Run Code Online (Sandbox Code Playgroud)

因为第二行在i.(A)中复制了值,而aPtr没有指向i.(A).

那么,为什么包含非​​指针值的接口不能成为带指针接收器的方法的接收器呢?由于存储在接口中的非指针值不可寻址,因此编译器无法将其地址传递给带有指针接收器的方法.

  • 感谢您解释而不是像其他人那样说“你应该问另一个问题”。 (3认同)
  • 正如我在帖子中指出的,“这是一个实施细节”,会带来严重后果 (2认同)