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

Pointers 使用指针接收器调用函数的Go语法,pointers,syntax,go,Pointers,Syntax,Go,在Go中,如果我定义了一个以指针作为接收器的函数,它不应该只允许从指针调用函数吗?为什么可以从值本身调用此函数并具有相同的效果 例如,在以下程序中:m1.reset()和m2.reset()具有相同的效果。即使m1是一个值,m2是一个指针 我有点困惑,因为做同一件事有两种方法,我不知道该遵循哪一种。尽管大多数代码遵循使用指针字段调用函数的约定。我错过什么了吗 package main import "fmt" type MyStruct struct { X

在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)
    }
规格:

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

关于的下一条必要信息是:

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


把上面两个东西放在一起,你就会看到你看到的行为。

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

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)
}
输出


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

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

m1.reset()
m2.reset()
进入:


您还可以添加,如果它不取消引用传递的接收器参数,
m*MyStruct
,以访问函数
reset()
定义内的字段
X
,如
(*m).X=0
。但这也是一种方便的速记或语法糖。还可以添加“它是否应该取消引用传递的接收方参数,
m*MyStruct
,以访问函数
reset
()定义内的字段
X
,如
(*m).X=0
?”。但这也是一种方便的速记或语法。
m1.reset()
m2.reset()
(&m1).reset()
m2.reset()