【问题标题】:Why interface don't implement method with pointer reference while direct access is still possible?为什么接口不使用指针引用实现方法,而直接访问仍然是可能的?
【发布时间】:2017-04-11 05:20:03
【问题描述】:

我知道接口没有按照 Go 规范和常见问题实现带有指针引用的方法,因为 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)
}

然后返回:

./main.go:26: 不能在 interfaceModify 的参数中使用 u(类型用户)作为类型修饰符: 用户没有实现修饰符(修改方法有指针接收器)

这解释为:

[…]方法调用没有获得指针的有用方法。

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

但是,将 interfaceModify(u) 替换为像 u.modify() 这样的直接调用确实有效:编译器获取 u 的地址,并会在 Println() 确认时修改其 name 属性。

因此,我们能够在这种精确的情况下执行该操作,但不能在界面一中执行。我对这种差异的唯一解释是,在interfaceModify(m modifier) 中,我们将直接将 u 复制到 m,而 m 没有办法调用modify()时匹配对应的地址。 因此,声明u := &user{"Default Name"} 会将指针(so 地址)u 复制到m,这就是为什么m.modify() 是可能的。 我说的对吗?

【问题讨论】:

    标签: go


    【解决方案1】:

    我想你已经明白了。 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)
    }
    

    【讨论】:

      【解决方案2】:

      T 类型不是 '&T' 类型。换句话说,指向 struct 的类型指针不是 struct 类型。因此,如果您决定使用指针接收器实现方法,则必须使用指针而不是结构本身,因为正是指针实现了该方法。您的代码只缺少一个字符。

      interfaceModify(u) 更改为interfaceModify(&u)

      playground

      【讨论】:

        猜你喜欢
        • 2015-08-04
        • 1970-01-01
        • 1970-01-01
        • 2020-06-07
        • 2015-10-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-26
        相关资源
        最近更新 更多