简单的界面
在 Go 中,接口只是一组方法。我们使用接口来指定给定对象的行为。
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{}
。这不包含任何方法,因此每个 type
都满足它。因此,空接口可以包含任何类型值。
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
的 h
,它可以存储 Human
或 OnlySinger.
类型的值。这是因为它们都实现了 Singer
接口指定的方法。
var h Singer
h = &human{}
h.Sing()