接口的定义
Go 的接口是一种抽象类型,它定义了一组方法签名,用来表示一种行为或功能。
用type
关键字定义的,后面跟着接口的名称和interface
关键字。
然后在花括号中列出方法签名,方法签名包括方法名,参数列表和返回值列表。
// 定义一个动物的接口
type animal interface {
// 动物可以叫
speak() string;
// 动物可以移动
move() string;
}
接口中只有方法签名,没有方法体
接口的实现
在 Go 中,接口的实现是隐式的,只要一个类型拥有了接口所要求的所有方法,就可以认为它实现了该接口。 接口类型的变量可以存储任何实现了该接口的值。
// 定义一个狗的结构体
type dog struct {
name string
}
// 为狗类型定义speak方法
func (d dog) speak() string {
return "汪!"
}
// 为狗类型定义move方法
func (d dog) move() string {
return "走"
}
// 定义一个猫的结构体
type cat struct {
name string
}
// 为猫类型定义speak方法
func (c cat) speak() string {
return "喵!"
}
// 为猫类型定义move方法
func (c cat) move() string {
return "跳"
}
这两个类型分别定义了speak
和move
方法,使它们满足 animal 接口的要求。
所以,我们就可以说 dog 和 cat 都实现了 animal 接口。
接口的使用
我们可以使用接口类型作为函数的参数或返回值,来实现多态和代码复用。
// 定义一个函数,接受一个animal类型的参数,并打印它的speak和move结果
func describe(a animal) {
fmt.Println(a.speak())
fmt.Println(a.move())
}
func main() {
d := dog{name: "旺财"}
c := cat{name: "小花"}
}
// 调用describe函数,并传入dog对象
describe(d)
// 输出:
// 汪!
// 跳
// 调用describe函数,并传入cat对象
describe(c)
// 输出:
// 喵!
// 跳
由于 dog 和 cat 都实现了 animal 接口,所以它们都可以作为 describe 函数的参数。这样我们就实现了多态和代码复用,不需要针对每种动物都写一个 describe 函数。
空接口
空接口是一种特殊的接口类型,它没有定义任何方法,因此任何类型都可以实现它。 空接口可以用来表示任意类型的值。
var any interface{}
类型断言
类型断言是一种操作,用来检查一个接口类型的变量是否存储了一个特定类型的值,并且可以将该值提取出来。 类型断言的语法是:
x.(T)
其中 x 是一个接口类型的变量,T 是一个类型。
如果 x 存储了一个 T 类型的值,那么这个操作会返回该值和 true。 如果 x 没有存储一个 T 类型的值,那么这个操作会返回零值和 false。 如果不关心断言是否成功,可以只使用一个变量来接收返回值。 如果断言失败且没有使用第二个变量来接收返回值,那么程序会发生 panic。
类型切换
类型切换是一种语句,用来根据一个接口类型的变量的实际类型执行不同的分支。 类型切换的语法是:
switch x.(type) {
case T1: ...
case T2: ...
default: ...
}
其中 x 是一个接口类型的变量,T1, T2 等是不同的类型。在每个分支中,x 会被转换为对应的类型,并且可以直接访问其方法或字段。如果没有匹配到任何分支,那么执行 default 分支。
接口嵌套
接口支持嵌套,可以将多个接口组合成一个新的接口。 接口嵌套的语法是:
type A interface {B; C; D}
其中 A, B, C, D 都是接口类型。这样定义后,A 就包含了 B, C, D 中定义的所有方法,并且任何实现了 A 的类型也必须实现 B, C, D 中定义的所有方法。