接收器 (receiver) 与接口
发布者:admin 发表于:417天前 阅读数:662 评论:0

使用值接收器的方法既可以通过值调用,也可以通过指针调用。

带指针接收器的方法只能通过指针或 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].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

Effective Go 中有一段关于 pointers vs. values 的精彩讲解。

补充:

一个类型可以有值接收器方法集和指针接收器方法集 值接收器方法集是指针接收器方法集的子集,反之不是

规则 值对象只可以使用值接收器方法集

指针对象可以使用 值接收器方法集 + 指针接收器方法集

接口的匹配(或者叫实现) 类型实现了接口的所有方法,叫匹配

具体的讲,要么是类型的值方法集匹配接口,要么是指针方法集匹配接口

具体的匹配分两种:

值方法集和接口匹配 给接口变量赋值的不管是值还是指针对象,都ok,因为都包含值方法集

指针方法集和接口匹配 只能将指针对象赋值给接口变量,因为只有指针方法集和接口匹配

如果将值对象赋值给接口变量,会在编译期报错(会触发接口合理性检查机制)

为啥 i = s2Val 会报错,因为值方法集和接口不匹配.