Go接口与多态
Go通过接口实现多态,不同类型可实现相同接口表现出不同行为。
多态基本概念
定义接口
Go
type Animal interface {
Speak() string
}
// 不同类型实现同一接口
type Dog struct{}
func (d Dog) Speak() string { return "汪汪" }
type Cat struct{}
func (c Cat) Speak() string { return "喵喵" }
type Cow struct{}
func (c Cow) Speak() string { return "哞哞" }
多态调用
Go
func makeSound(a Animal) {
fmt.Println(a.Speak())
}
func main() {
makeSound(Dog{}) // 汪汪
makeSound(Cat{}) // 喵喵
makeSound(Cow{}) // 哞哞
}
同一函数接受不同类型,表现出不同行为。
接口赋值
值类型赋值
Go
var a Animal = Dog{} // 值赋值
a.Speak() // "汪汪"
// Dog{}满足Animal接口
指针类型赋值
Go
var a Animal = &Dog{} // 指针赋值
a.Speak() // "汪汪"
// *Dog也满足Animal接口
接口变量存储
Go
var animals []Animal
animals = append(animals, Dog{})
animals = append(animals, Cat{})
animals = append(animals, &Cow{})
for _, a := range animals {
fmt.Println(a.Speak())
}
动态调用原理
接口内部结构
Go
// 接口包含类型信息和数据指针
type iface struct {
tab *itab // 接口表(包含方法地址)
data unsafe.Pointer // 数据指针
}
// 方法调用时:
// 1. 从itab查找方法地址
// 2. 调用具体类型的实现
动态调用示例
Go
var a Animal
a = Dog{}
a.Speak() // 调用Dog.Speak
a = Cat{}
a.Speak() // 调用Cat.Speak
// 编译时不知道具体类型
// 运行时动态查找方法
多态应用场景
策略模式
Go
type Sorter interface {
Sort([]int) []int
}
type QuickSort struct{}
func (q QuickSort) Sort(data []int) []int {
// 快速排序实现
return data
}
type BubbleSort struct{}
func (b BubbleSort) Sort(data []int) []int {
// 冒泡排序实现
return data
}
func sortData(data []int, sorter Sorter) []int {
return sorter.Sort(data)
}
插件模式
Go
type Plugin interface {
Name() string
Execute(input string) string
}
func runPlugin(p Plugin, input string) {
fmt.Println("执行:", p.Name())
output := p.Execute(input)
fmt.Println("结果:", output)
}
Mock测试
Go
type Repository interface {
Find(id int) (*User, error)
Save(user *User) error
}
// 真实实现
type MySQLRepo struct{}
// Mock实现(测试)
type MockRepo struct{}
func (m MockRepo) Find(id int) (*User, error) {
return &User{Name: "Mock"}, nil
}
// 测试时使用Mock
func TestService(t *testing.T) {
repo := MockRepo{}
service := NewService(repo)
// 测试逻辑...
}
多态优势
| 优势 | 说明 |
|---|---|
| 解耦 | 调用者不依赖具体类型 |
| 扩展 | 新类型满足接口即可 |
| 测试 | Mock实现替代真实类型 |
| 简洁 | 统一接口简化调用 |
多态注意事项
方法必须完全匹配
Go
type Reader interface {
Read(p []byte) (int, error)
}
// 方法签名必须完全一致
type MyReader struct{}
func (m MyReader) Read(p []byte) (int, error) {
return len(p), nil
}
// 以下不满足Reader接口
func (m MyReader) Read(p []byte) int {
return len(p) // 返回值不匹配
}
空接口与多态
Go
// 空接口接受任何类型
var i interface{} = Dog{}
var j interface{} = 42
// 但无法调用方法(空接口无方法)
// i.Speak() // 编译错误
要点总结
- 接口实现多态,不同类型相同行为
- 值类型和指针类型都可赋给接口
- 方法签名必须完全匹配接口
- 接口变量存储类型信息和数据指针
- 动态调用在运行时查找方法地址
- 多态用于策略模式、插件、Mock测试
- 新类型满足接口即可扩展,无需修改调用者
📝 发现内容有误?点击此处直接编辑