模块 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 多态性:接口类型参数,无层次结构。