Go语言3-接口

Go语言的主要设计者之一罗布·派克(Rob Pike)曾经说过,如果只能选择一个Go语言的特性移植到其他语言中,他会选择接口,所以接口在Go语言有着至关重要的地位。 –《go语言编程》

先来看看java中的接口,它定义了一个契约,就像USB口,使用方不需要关注具体实现,直接通过接口访问。但java中实现类必须显示实现接口,也就是说针对接口做开发,如果不知道接口长什么样子,实现就属白扯。

GO语言的接口不太一样,不需要显示依赖(导入包)或者用关键词implement声明,只要实现了接口的所有方法,就说这个类型实现了该接口。

实现

接口是用来定义行为的,一是定义,具体实现通过方法。对接口方法的调用会执行接口里存储的用户定义的类型的对应的方法。因为任何用户定义的类型都可以实现任何接口,所以对接口方法的调用自然就是一种多态。

接口 是一个两个字长度 的数据结构,第一个字包含一个指向内部表结构的指针,这个内部表里存储的有实体类型的信息以及相关联的方法集;第二个字包含的是一个指向存储的实体类型值的指针。所以接口的值结构其实是两个指针,这也可以说明接口其实一个引用类型。

方法集

如果要实现一个接口,必须实现这个接口提供的所有方法,但是实现方法的时候,我们可以使用指针接收者实现,也可以使用值接收者实现。
先看个示例:

package main

import (
	"fmt"
)

type notifier interface {
	notify()
}
type user struct {
	name string
	email string
}

func (u *user) notify()  {
	fmt.Println("Sending user email to %s<%s>\n",u.name,u.email)
}
func sendNotification(n notifier)  {
	n.notify()
}
func main()  {
	u := user{"Bill","bill@email.com"}
	sendNotification(u)
}

编译错误:
src/hello/hello.go:23: cannot use u (type user) as type notifier in argument to sendNotification:
user does not implement notifier (notify method has pointer receiver)

错误已经写明,notify方法是一个指针接收者。

如果把sendNotification(u)改成sendNotification(&u),正常输出结果。
如果把

func (u *user) notify()  {
	fmt.Println("Sending user email to %s<%s>\n",u.name,u.email)
}

改成

func (u user) notify()  {
	fmt.Println("Sending user email to %s<%s>\n",u.name,u.email)
}

则不管传递指针还是值都一样。所以,go语言对接口做了这样的规定:如果是值接收者,实体类型的值和指针都可以实现对应的接口;如果是指针接收者,那么只有类型的指针能够实现对应的接口。

反过来说:类型的值只能实现值接收者的接口,指向类型的指针,既可以实现值接收者的接口,也可以实现指针接收者的接口


[1]. 《Go语言实战》笔记
[2]. 《Go语言实战》

CONTENTS