值接收者指针接收者指针类型值接收者方法指针接收者方法值类型值接收者方法值类型指针接收者方法

类型不同可以调用

package main

import (
	"fmt"
)

type field struct {
	name string
}

func (p *field) pointerMethod() {
	fmt.Println(p.name)
}

func (p field) valueMethod() {
	fmt.Println(p.name)
}

func main() {
	fp := &field{name: "pointer"}
	fv := field{name: "value"}

	fp.pointerMethod()
	fp.valueMethod()
	fv.pointerMethod()
	fv.valueMethod()
}
//output: pointer pointer value value
fieldpointerMethodvalueMethod
fpfv
fpfvpointerMethodvalueMethod

当类型和方法的接收者类型不同时,编译器会做一些操作:

值类型指针接收者方法(&fv).pointerMethod()
指针类型值接收者方法(*fp).valueMethod()

这里是类型不同可以相互调用的情况,再说下不能调用的情况。

类型不同不可以调用

不能调用的情况有两种:

值类型指针接收者
值类型指针接收者方法
值类型

如果值类型实体不能被寻址,那么它就不能调用指针接收者方法

package main

import (
	"fmt"
)

type field struct {
	name string
}

func (p *field) pointerMethod() {
	fmt.Println(p.name)
}

func (p field) valueMethod() {
	fmt.Println(p.name)
}

func NewFiled() field {
	return field{name: "right value struct"}
}

func main() {
	NewFiled().valueMethod()
	NewFiled().pointerMethod()
}

运行代码报错:

./x.go:37:12: cannot call pointer method on NewFiled()
./x.go:37:12: cannot take the address of NewFiled()
NewFoo()
指针接收者

使用指针接收者实现接口方法,那么只有指针类型的实体实现了接口

package main

import "fmt"

type human interface {
	speak()
	sing()
}

type man struct {
}

func (m man) speak() {
	fmt.Println("speaking")
}

func (m *man) sing() {
	fmt.Println("singing")
}

func main() {
	var h human = &man{}
	h.speak()
	h.sing()
}

 

&man{}man{}
func main() {
	var h human = man{}
	h.speak()
	h.sing()
}

 

报错如下:

./x.go:22:6: cannot use man literal (type man) as type human in assignment:
        man does not implement human (sing method has pointer receiver)
manhumansing

这里看下飞雪无情的总结:

实体类型以指针接收者实现接口的时候,只有指向这个类型的指针才被认为实现了该接口

如果是值接收者,实体类型的值和指针都可以实现对应的接口;如果是指针接收者,那么只有类型的指针能够实现对应的接口

再看下饶大的解释:

接收者是指针类型的方法,很可能在方法中会对接收者的属性进行更改操作,从而影响接收者;而对于接收者是值类型的方法,在方法中不会对接收者本身产生影响。

所以,当实现了一个接收者是值类型的方法,就可以自动生成一个接收者是对应指针类型的方法,因为两者都不会影响接收者。但是,当实现了一个接收者是指针类型的方法,如果此时自动生成一个接收者是值类型的方法,原本期望对接收者的改变(通过指针实现),现在无法实现,因为值类型会产生一个拷贝,不会真正影响调用者。

平时我们写代码的时候也不用可以记这个,不仅编译器会报错,goland也一样会提示。

参考

https://www.qtmuniao.com/2020/01/06/go-value-pointer-method/

https://qcrao91.gitbook.io/go/interface/zhi-jie-shou-zhe-he-zhi-zhen-jie-shou-zhe-de-qu-bie

https://www.flysnow.org/2017/04/03/go-in-action-go-interface.html