简单接口

在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。

最后更新于