接口是指针

看个例子:

type Animal interface {
	foo()
	bar()
}

type People struct {
	name string
	age int
}

func (p *People) foo() {
	// ...
}

func (p People) bar() {
	// ...
}

func main() {
	var a Animal = &People{}
	a.foo()
	a.bar()
}

我们可以看到 foo 和 bar 方法的接收者一个是指针类型,一个是值类型,但是如果我们把接口体指针赋给接口,我们会发现这个接口可以调用的方法既有指针类型的接收者又有值类型的接收者,可以发现当指向结构体当指针赋给接口的时候,接口具有更广的调用方法的能力

接口是值

同样我们看下例子

type Animal interface {
	foo()
	bar()
}

type People struct {
	name string
	age int
}

func (p People) foo() {
	// ...
}

func (p People) bar() {
	// ...
}

func main() {
	var a Animal = People{}
	a.foo()
	a.bar()
}

这一段代码与最上面的那段代码有什么不同呢?可以发现 foo 方法的接收者从指针类型变成值类型,因为如果将结构体的值赋给接口,并且接口实现的方法的接收者中是指针类型,则在程序在编译的时候就会报错,因此如果我将结构体值赋给接口时候,结构体实现所有接口方法的方法接收者就不得不是值类型了,所以不得不把 foo 原本指针的方法接收者改成值类型的方法接收者,这样才可以让 foo 方法和 bar 方法成功运行

总结

当指向结构体的指针赋给接口时候比结构体值赋给接口时候具有更「强」的调用方法的能力

「强」体现在此接口(指针)调用的方法,这些方法的接收者即可以是指针类型接收者又可以是值类型接收者,而值类型的接口只能调用的方法,其接收者只可以是值类型,并且值类型的接口如果存在实现方法的接收者是指针的时候,值类型接口在编译时候根本不可能生成

最后再简单的换言之,如果值类型接口能够满足所有实现的方法,那么指针类型接口也一定能够满足;指针类型接口比值类型接口具有更广泛调用方法的能力;如果实现接口方法的接收者是指针则接口必须是指向结构体的指针,该方法才会被实现,如果仅仅只有结构体值,则该方法不是实现接口的方法,或者可以简单理解是指针类型结构体实现了接口方法而不是值类型结构体实现