一尘不染

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

go

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

“以相同的方式,存储在接口中的具体值不可寻址,即映射元素不可寻址。”

但是,关于接口尚不清楚。为什么无法寻址?这是因为某些硬性设计假设吗?


阅读 282

收藏
2020-07-02

共1个答案

一尘不染

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

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

tl; dr

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

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

长答案

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

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

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

另一个常见的答案是:

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

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

那么,为什么不能将值存储在接口中呢?答案就在于在后续影响,如果它 可寻址。

假设您有一个接口 I 和两个满足该接口的类型 A B

type I interface{}
type A int
type B string

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

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

假设我们可以采用存储在接口中的值的地址:

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

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

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

这是输出:

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

B 放入 i后 aPtr 指向什么? aPtr 被声明为指向 A ,但是
t
现在包含 B ,并且 aPtr 不再是指向 A 的有效指针。

但是,这是允许的:

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

因为第二行复制了 i。(A) 中的值,并且 aPtr 没有指向 i。(A)

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

2020-07-02