Go 的接口设计是其最具特色的语言特性之一。隐式接口满足让代码解耦变得更加自然——实现者不需要声明自己实现了哪个接口。
隐式接口的力量
type Reader interface {
Read(p []byte) (n int, err error)
}
// MyReader 自动满足 Reader 接口,无需显式声明
type MyReader struct{}
func (m MyReader) Read(p []byte) (int, error) {
return copy(p, "hello"), nil
}
接口设计的黄金法则
- 接受接口,返回结构体:函数应该接受最小的接口类型作为参数,返回具体的结构体。
- 按需定义接口:在使用方定义接口,而不是在实现方。
- 接口要小:单方法接口是 Go 的习惯,如 io.Reader、io.Writer。
类型断言与类型切换
类型断言可以在运行时检查接口值的具体类型。类型切换则提供了一种简洁的方式来处理多种类型。
switch v := x.(type) {
case int:
fmt.Println("integer:", v)
case string:
fmt.Println("string:", v)
default:
fmt.Printf("unknown type: %T\n", v)
}
接口与泛型
Go 1.18 引入泛型后,接口的角色有所扩展。泛型在编译期决定类型,适合算法抽象;接口在运行时决定,适合行为抽象。两者互补而非替代。
小而精准的接口是 Go 设计的精髓——接受最小的需求,提供最大的能力。