接口

接口 属于 Go

2 个练习

关于 接口

接口是一组方法

最简单的形式下,接口类型就是一组方法签名。 下面是一个接口定义的例子,其中包含Add和Value两个方法:

type Counter interface {
    Add(increment int)
    Value() int
}

像increment这样的形参名可以从接口定义中省略,但它们往往能提高可读性。

Go 中的接口名不包含Interface或I这样的单词。 相反,它们通常以er结尾,例如Reader、Stringer。

实现接口

任何定义了接口中那些方法的类型,都会自动隐式地“实现”这个接口。 Go 中没有implements关键字。

下面这个类型实现了我们前面看到的Counter接口。

type Stats struct {
    value int
    // ...
}

func (s Stats) Add(v int) {
    s.value += v
}

func (s Stats) Value() int {
    return s.value
}

func (s Stats) SomeOtherMethod() {
    // The type can have additional methods not mentioned in the interface.
}

要实现接口,方法使用值接收者还是指针接收者都无所谓。 (如果对此不太确定,可以回头看看方法概念。)

接口类型的值可以保存任何实现了这些方法的值。1

也就是说,凡是需要Counter接口的地方,现在都可以使用Stats。

func SetUpAnalytics(counter Counter) {
    // ...
}

stats := Stats{}
SetUpAnalytics(stats)
// works because Stats implements Counter

如果函数的所有形参和返回值都必须使用具体类型(即非接口类型),那会严重限制它们的可复用性。 把形参声明为接口类型,就只定义了函数完成工作所必需的行为。 这样一来,只要不同的具体类型实现了该接口,这个函数就能接收它们作为形参。 把接口类型用作返回值时,也是同样的道理。

由于接口是隐式实现的,一个类型可以轻松实现多个接口。 它只需要定义好全部必需的方法即可。

组合接口

接口定义可以包含其他接口。 下面是标准库中的一个例子。

type ReadCloser interface {
	Reader
	Closer
}

// Based on these interfaces:

type Reader interface {
	Read(p []byte) (n int, err error)
}

type Closer interface {
	Close() error
}

定义ReadCloser时,接口定义没有重复写Read和Close的方法签名,而是复用了已有的Reader和Closer定义。

空接口

Go 中有一种非常特殊的接口类型,即不包含任何方法的空接口。 空接口的写法是这样的:interface{}。 在 Go 1.18 及更高版本中,也可以使用any。 它被定义为一个别名。

由于空接口没有任何方法,所以每个类型都隐式地实现了它。 这对于定义一个能通用地接受任意值的函数很有用。 这种情况下,函数的形参就使用空接口类型。

例如:

func AnythingGoes(i interface{}) string {
    if i == 0 {
        return "zero"
    }
    if i == "" {
        return "empty string"
    }
    return "something else"
}
  1. Tour of Go: Interfaces ↩

通过 GitHub 编辑 该链接会在新窗口或标签页中打开

学习 接口

练习已锁定

再解锁 1 个练习即可练习 接口