# 简单接口

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

{% hint style="info" %}
#### 译者提示

接口首先是一种类型(type)，跟 int、string 等类型的地位一样；其次它是程序员用来对某种对象的行为进行抽象建模的工具；最后，Go的接口与其他语言的接口不同，Go接口只允许对行为抽象（内部只能声明方法），不允许对数据抽象。

简单说，其他语言的Interface是Class的模板，Class是object的模板，而且它们在定义Interface或Class的时候，可以同时对行为和数据建模。

**而Go语言，其Interface定义时只能对行为建模，Struct定义时只允许对数据建模，然后再为Struct添加方法（隐式实现interface），再然后初始化Struct，最终得到的Struct实体才同时具备了行为和数据。**
{% endhint %}

```go
type Painter interface {
    Paint()
}
```

要实现接口的类型**不需要**显式地声明自己要实现某接口了。为该类型定义与接口中相同的方法名和方法签名就可以了。

```go
type Rembrandt struct{}

func (r Rembrandt) Paint() {
    // use a lot of canvas here
}
```

现在我们就可以将该结构体作为接口使用：

```go
var p Painter
p = Rembrandt{}
```

一个接口可以被任意个类型实现，一个类型也可以实现任意个接口。

```go
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{}`来声明一个空接口。由于空接口没有方法，所以任何类型都可以适配它。因此，空接口可以用来存放任何类型的值。

```go
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"}
```

接口最常见的使用场景是，用于确保某变量支持一个或多个特定的行为。相比之下，空接口的主要使用场景是，用于定义可以容纳任何值的变量，而忽视变量的具体类型。

如果想得到空接口所存变量的原始类型，像下面这样就行：

```go
i = a.(int)
s = a.(string)
m := a.(*StructType)
```

或者

```go
i, ok := a.(int)
s, ok := a.(string)
m, ok := a.(*StructType)
```

`ok`表示`interface a`是否可以转换为给定类型，如果不能转则`ok`的值为`false`。

## 接口值

如果您定义了一个接口类型的变量，它可以存储实现了接口声明的方法的任何类型的值。

例如我们声明了`interface Singer`的变量`h`，`h`既能够存放`Human`的变量，也能存放`OnlySinger`的。这是因为`Human`和`OnlySinger`都实现了`Singer`接口规定的方法。

```go
var h Singer
h = &human{}

h.Sing()
```

{% hint style="info" %}
#### 译者提示：鸭子类型

Go 的Interface又称鸭子类型，这是一种动态类型编程风格，如Python。
{% endhint %}
