为什么在仍然可以直接访问的情况下,接口不使用指针引用实现方法?

did*_*cks 3 go

我确实了解接口不会按照Go规范和FAQ来实现带有指针引用的方法,因为T和* T具有不同的方法集(https://golang.org/doc/faq#guarantee_satisfies_interface)。

因此,这不起作用:

package main

import (
    "fmt"
)

type user struct {
    name string
}

type modifier interface {
    modify()
}

func (u *user) modify() {
    u.name = "My name"
}

func interfaceModify(m modifier) {
    m.modify()
}

func main() {
    u := user{"Default Name"}

    interfaceModify(u)
    fmt.Println(u.name)
}
Run Code Online (Sandbox Code Playgroud)

并返回:

./main.go:26:无法在接口修改的参数中使用u(类型用户)作为类型修饰符:用户未实现修饰符(modify方法具有指针接收器)

解释为:

[…]没有有效的方法调用来获取指针。

即使在编译器可以将值的地址传递给方法的情况下,如果方法修改了该值,则更改也将在调用方中丢失。

但是,用interfaceModify(u)类似的直接调用替换u.modify()确实可行:编译器采用u的地址,并在Println()确认时修改其name属性。

因此,我们能够在那种精确的情况下执行该操作,但不能在接口之一中进行。我对这种区别的唯一解释是,在中interfaceModify(m modifier),我们将把u直接复制到m,并且在调用时m无法匹配相应的地址modify()。因此,声明u := &user{"Default Name"}将因此将指针(so地址)u复制到m,这m.modify()就是可能的原因。我对么?

小智 5

我想你已经明白了。u.modify()之所以有效,是因为go将其视为简写(&u).modify()interfaceModify(&u)也可以。这是一个操场,其中有更多通过引用与价值传递的示例。

https://play.golang.org/p/HCMtcFAhLe

package main

import (
    "fmt"
)

type user struct {
    name string
}

type userPointer struct {
    user
}

func (up *userPointer) modify() {
    up.name = "My name"
}

type modifier interface {
    modify()
}

func (u user) modify() {
    u.name = "My name"
}

func interfaceModify(m modifier) {
    m.modify()

}

func main() {
    u := user{"Default Name"}
    u.modify()
    fmt.Println(u.name)
    interfaceModify(u)
    fmt.Println(u.name)

    up := userPointer{user{"Default Name"}}
    interfaceModify(&up)
    fmt.Println(up.name)
    // short hand version
    up.name = "Default Name"
    up.modify()
    fmt.Println(up.name)
    // long hand version https://golang.org/ref/spec#Calls
    up.name = "Default Name"
    (&up).modify()
    fmt.Println(up.name)
}
Run Code Online (Sandbox Code Playgroud)