Go用指针接收器调用函数的语法



在Go中,如果我定义了一个以指针为接收器的函数,它不应该只允许从指针调用该函数吗?为什么可以从值本身调用此函数并具有相同的效果。

例如,在以下程序中:m1.reset()&m2.reset()具有相同的效果。即使m1是一个值,m2是一个指针。

我有点困惑,因为有两种方法可以做同样的事情,我不确定该遵循哪一种。尽管大多数代码遵循惯例,即使用指针字段调用函数。我是不是错过了什么?

package main
    import "fmt"
    type MyStruct struct {
        X int
    }
    func (m *MyStruct) reset() {
        m.X = 0
    }
    func main() {
        m1 := MyStruct{1}
        m2 := &MyStruct{1}
        fmt.Println(m1.X)
        fmt.Println(m2.X)
        m1.reset()
        m2.reset()
        fmt.Println(m1.X)
        fmt.Println(m2.X)
    }

@jnml提供了完美的文档规范解释,但我想添加一个基于您的代码示例。我认为你的重点不应该是"为什么有两种方法可以做同样的事情",而应该更多地关注何时使用其中一种方法。将指针作为接收器的方法有能力修改该接收器的值,而将值作为接收器的方式则不能。这是因为方法接收接收器的副本。当您获得指针的副本时,您仍然可以修改其值。当您收到值的副本时,您在该方法中所做的更改只会更改副本,而不会更改原始值:

package main
import "fmt"
type MyStruct struct {
    X int
}
func (m *MyStruct) resetPtr() {
    m.X = 0
}
func (m MyStruct) resetValue() {
    m.X = 0
}
func main() {
    m1 := MyStruct{1}
    m2 := &MyStruct{1}
    fmt.Println("Original Values:", m1.X, m2.X)
    m1.resetPtr()
    m2.resetPtr()
    fmt.Println("After resetPtr():", m1.X, m2.X)
    m1 = MyStruct{1}
    m2 = &MyStruct{1}
    m1.resetValue()
    m2.resetValue()
    fmt.Println("After resetValue():", m1.X, m2.X)
}

输出

Original Values: 1 1
After resetPtr(): 0 0
After resetValue(): 1 1

您可以看到,访问这些变量的方式并不是真正的问题。更多的是关于如何在方法内部处理它们,以及如何将它们作为参数传递给其他函数或方法(被复制)。

Specs说:

对应指针类型*T的方法集是所有具有接收器*T或T的方法的集合(即,它也包含T的方法集合)。

关于方法调用的下一条必要信息是:

如果(的类型)x的方法集包含m并且参数列表可以被分配给m的参数列表,则方法调用CCD_ 1是有效的;x的方法集包含m,x.m()(&x).m()的简写。

把上面两件事放在一起,你就会得到你所看到的行为。

一个简短的解释是Go编译器在后台自动转换:

m1.reset()
m2.reset()

进入:

(&m1).reset()
m2.reset()

最新更新