LLLeon / Blog

LLLeon 的部落格
15 stars 4 forks source link

Go 中关于方法的 receiver 的总结 #11

Open LLLeon opened 6 years ago

LLLeon commented 6 years ago

关于这部分内容,在写代码时一直都是用指针类型的 receiver,但没有系统整理过规则,这里进行总结。

首先是官方 FAQ 中说的那三条:

还有一些其它的规则:

下面看两个比较容易搞混的例子:

package main

import (
    "fmt"
)

type Ball struct {
    Name string
}

func (b *Ball) Ping() {
    fmt.Println("ping")
}

func (b Ball) Pong() {
    fmt.Println("pong")
}

func main() {
    v := Ball{}
    p := &Ball{}

    v.Ping()
    v.Pong()

    p.Ping()
    p.Pong()
}

运行结果是都可以正常执行:

❯ go run test.go
ping
pong
ping
pong

也就是说,struct 的实例和实例指针都可以调用值类型和指针类型 receiver 的方法。

再看这段代码,这里是通过 method expression 的方式调用方法:

package main

import (
    "fmt"
)

type Ball struct {
    Name string
}

func (b *Ball) Ping() {
    fmt.Println("ping")
}

func (b Ball) Pong() {
    fmt.Println("pong")
}

func main() {
    v := Ball{}

    Ball.Ping(&v)
    Ball.Pong(v)
}

这次的执行结果呢?

❯ go run test.go
# command-line-arguments
./t.go:23:6: invalid method expression Ball.Ping (needs pointer receiver: (*Ball).Ping)
./t.go:23:6: Ball.Ping undefined (type Ball has no method Ping)

可以看到,通过 method expression 的方式,struct 值只能调用值类型 receiver 的方法。

再看 struct 指针调用方法:

func main() {
    p := &Ball{}

    (*Ball).Ping(p)
    (*Ball).Pong(p)
}

执行结果:

❯ go run test.go
ping
pong

即 struct 指针是能调用值类型和指针类型 receiver 的方法的。

但在写代码时,不建议使用 method expression 这种方式来调用方法。不过应该也没有人会用这种方式的...吧?