接收器为值和指针的方法在调用方式上是有区别的。

使用值接收器的方法既可以通过值调用,也可以通过指针调用。带指针接收器的方法只能通过指针或 addressable values 调用。

type S struct {
  data string
}

func (s S) Read() string {
  return s.data
}

func (s *S) Write(str string) {
  s.data = str
}

sVals := map[int]S{1: {"A"}}

// 你只能通过值调用 Read。
sVals[1].Read()

// 编译不通过,因为无法对 sVals[1] 取址。
//  sVals[1].Write("test")

sPtrs := map[int]*S{1: {"A"}}

// 指针既可以调用 Read,也可以调用 Write。
sPtrs[1].Read()
sPtrs[1].Write("test")

类似的,使用值接收器和指针接收器来实现接口,在判断与接口是否匹配时,也存在一定的区别。

type F interface {
  f()
}

type S1 struct{}

func (s S1) f() {}

type S2 struct{}

func (s *S2) f() {}

s1Val := S1{}
s1Ptr := &S1{}
s2Val := S2{}
s2Ptr := &S2{}

var i F
i = s1Val
i = s1Ptr
i = s2Ptr

// 下面代码无法通过编译,因为 s2Val 是一个值,而 S2 的 f 方法中没有使用值接收器。
// i = s2Val

从前文可知,可取址的值可以调用接收器为指针的方法,但这里为何不能将值 s2Val 赋给接口 i 呢?

在 Effective Go 中一节 Pointers vs. Values 做了说明,因为接收器为指针的方法会修改接受器,为了避免产生这种错误的行为,便禁止将值赋给和指针接收器方法集匹配的接口。

powered by Gitbook该文章修订时间: 2024-08-04 07:27:05

results matching ""

    No results matching ""