跳转到主要内容
模块 6 · 第 1 课(共 5)课程中的26/50~12 min
模块课程(1/5)

接口:定义行为

Go 中的接口是一组方法签名。一个值 如果接口具有 所有 这些方法,则实现该接口 - 否 implements,无extends,无显式注册。这是 模型通常称为“结构类型”或“静态鸭子类型”: 编译器在编译时检查一致性,但基于 形状,而不是声明。

声明一个接口

Go
type Greeter interface {
    Greet() string
}

约定:对于单方法接口,名称以 -er 结尾 (Reader、Writer、Stringer、Closer)。接口小 (1-2 方法)是惯用:标准库充满了 组合在一起的微小接口(io.ReadWriter, io.ReadCloser,...)。

隐式实现

Go
type Person struct{ Name string }

func (p Person) Greet() string {
    return "ciao " + p.Name
}

// Person satisfies Greeter because it has the required method.
var s Greeter = Person{Name: "Ada"}
fmt.Println(s.Greet())

没有关键字。如果类型具有方法,则可以将其分配给 该接口类型的变量。就是这样。

通过接口实现多态性

Go
type Robot struct{ ID string }
func (r Robot) Greet() string { return "bip " + r.ID }

func greet(s Greeter) {
    fmt.Println(s.Greet())
}

greet(Person{Name: "Ada"})
greet(Robot{ID: "R2"})

greet 接受任何满足 Greeter 的类型。这就是Go方式 进行多态性:没有层次结构,只有能力。

空接口

Go
var x interface{} = 42
var y any = "ciao"   // any is the built-in alias of interface{}

interface{} (或 any 自 Go 1.18 起)不需要任何方法,因此任何 值满足它。对于通用容器很有用,但要提取 您需要 类型断言 或 类型开关 的具体值 (下一课)。

方法集:值与指针接收器(预览)

回顾第 5 单元:

  • 具有值接收器的方法位于 T 和 *T 的方法集中。
  • 具有 指针接收器 的方法仅位于 *T 的方法集中。

实际后果:

Go
type Counter struct{ N int }
func (c *Counter) Inc() { c.N++ }

type Incrementer interface { Inc() }

var i Incrementer = &Counter{}   // OK: *Counter has Inc()
// var j Incrementer = Counter{} // ERROR: Counter (value) does NOT

当方法有指针接收器时,必须分配一个指针 接口变量。

尝试一下

锻炼#go.m6.l1.e1
尝试:0加载中...

使用单个方法 Greet() 字符串定义接口 Greeter。

正在加载编辑器...
显示提示

语法:`type Name interface { Method(args) return }`。

3 次尝试后可用的解决方案

锻炼#go.m6.l1.e2
尝试:0加载中...

在带有字段 ID 字符串的新型机器人上实现 Greeter;该方法返回“bip”+ ID。

正在加载编辑器...
显示提示

没有“implements”:只需使用正确的签名定义方法即可。

3 次尝试后可用的解决方案

Quiz#go.m6.l1.e3
准备好

如何声明类型 P 实现 Greeter 接口?

Go
type P struct{}
// ?
答案选项

回顾

  • 接口 = 方法签名集;没有 implements。
  • 隐式实现:只需具有正确签名的方法。
  • 惯用语:小接口(1-2 个方法),名称在 -er 中。
  • interface{} / any:接受任何值,失去类型安全性。
  • 方法集:指针接收者→只有*T满足接口。
  • Go 多态性:接口类型参数,无层次结构。