简单接口

在Go中,接口仅仅是一种包含了一组方法声明的类型。我们用接口来制定给定对象的行为。

译者提示

接口首先是一种类型(type),跟 int、string 等类型的地位一样;其次它是程序员用来对某种对象的行为进行抽象建模的工具;最后,Go的接口与其他语言的接口不同,Go接口只允许对行为抽象(内部只能声明方法),不允许对数据抽象。
简单说,其他语言的Interface是Class的模板,Class是object的模板,而且它们在定义Interface或Class的时候,可以同时对行为和数据建模。
而Go语言,其Interface定义时只能对行为建模,Struct定义时只允许对数据建模,然后再为Struct添加方法(隐式实现interface),再然后初始化Struct,最终得到的Struct实体才同时具备了行为和数据。
type Painter interface {
Paint()
}
要实现接口的类型不需要显式地声明自己要实现某接口了。为该类型定义与接口中相同的方法名和方法签名就可以了。
type Rembrandt struct{}
func (r Rembrandt) Paint() {
// use a lot of canvas here
}
现在我们就可以将该结构体作为接口使用:
var p Painter
p = Rembrandt{}
一个接口可以被任意个类型实现,一个类型也可以实现任意个接口。
type Singer interface {
Sing()
}
type Writer interface {
Write()
}
type Human struct{}
func (h *Human) Sing() {
fmt.Println("singing")
}
func (h *Human) Write() {
fmt.Println("writing")
}
type OnlySinger struct{}
func (o *OnlySinger) Sing() {
fmt.Println("singing")
}
上述代码中,Human结构体既实现了Singer接口也实现了Writer接口,而OnlySinger结构体只实现了Singer接口。

空接口

还存在一种称为空接口的类型,它是指不包含任何方法的接口。我们通过interface{}来声明一个空接口。由于空接口没有方法,所以任何类型都可以适配它。因此,空接口可以用来存放任何类型的值。
var a interface{}
var i int = 5
s := "Hello world"
type StructType struct {
i, j int
k string
}
// all are valid statements
a = i
a = s
a = &StructType{1, 2, "hello"}
接口最常见的使用场景是,用于确保某变量支持一个或多个特定的行为。相比之下,空接口的主要使用场景是,用于定义可以容纳任何值的变量,而忽视变量的具体类型。
如果想得到空接口所存变量的原始类型,像下面这样就行:
i = a.(int)
s = a.(string)
m := a.(*StructType)
或者
i, ok := a.(int)
s, ok := a.(string)
m, ok := a.(*StructType)
ok表示interface a是否可以转换为给定类型,如果不能转则ok的值为false

接口值

如果您定义了一个接口类型的变量,它可以存储实现了接口声明的方法的任何类型的值。
例如我们声明了interface Singer的变量hh既能够存放Human的变量,也能存放OnlySinger的。这是因为HumanOnlySinger都实现了Singer接口规定的方法。
var h Singer
h = &human{}
h.Sing()

译者提示:鸭子类型

Go 的Interface又称鸭子类型,这是一种动态类型编程风格,如Python。