Go通过接口隐式实现和运行时类型分发模拟多态:定义含明确方法签名的接口,多个struct隐式实现它;接口值存切片或map中统一调用,行为由实际类型决定;支持接口嵌入组合能力,但不自动传递实现。

Go 里没有传统面向对象的“多态”,但接口能达成等效效果
Go 不支持类继承和方法重载,所谓“多态”是靠接口的隐式实现 + 运行时类型分发来模拟的。关键不是“怎么写得像 Java”,而是“如何让不同结构体响应同一接口调用”。interface{} 是万能空接口,但真正有用的多态必须定义**有明确方法签名的自定义接口**。
定义接口并让多个 struct 隐式实现它
Go 接口是隐式实现的:只要某个类型提供了接口要求的所有方法(签名一致),就自动满足该接口,无需 implements 或 extend 声明。这是多态落地的前提。
- 接口方法签名必须完全匹配:包括参数名(可省略)、类型、顺序,以及返回值数量与类型
- 接收者类型要一致:比如接口要求
func (t T) Speak(),那只有值接收者T或指针接收者*T能实现——但二者不能混用 - 常见错误:给
*Animal定义了Move(),却用Animal{}值类型变量去赋值接口,导致编译失败:cannot use Animal literal (type Animal) as type Mover in assignment: Animal does not implement Mover (Move method has pointer receiver)
type Speaker interface {
Speak() string
}
type Dog struct{ Name string }
func (d Dog) Speak() string { return d.Name + " says woof!" }
type Cat struct{ Name string }
func (c Cat) Speak() string { return c.Name + " says meow!" }
// 两者都隐式实现了 Speaker,可直接用于同一上下文
func saySomething(s Speaker) { println(s.Speak()) }
saySomething(Dog{Name: "Buddy"}) // ok
saySomething(Cat{Name: "Luna"}) // ok
用切片或 map 存储不同实现,统一调用
把满足同一接口的不同类型实例放进 []Speaker 或 map[string]Speaker,就能在循环中统一调用 Speak(),行为由实际类型决定——这就是运行时多态的核心表现。
- 切片元素必须是接口类型,不是具体 struct;否则无法混存
- 注意值 vs 指针:若实现方法用指针接收者,存入切片时必须传地址,如
&Dog{...} - 性能影响极小:接口值本质是
(type, data)两字宽结构,调用方法走的是动态查找表(itable),开销可忽略
animals := []Speaker{
Dog{Name: "Max"},
Cat{Name: "Nala"},
Dog{Name: "Charlie"},
}
for _, a := range animals {
println(a.Speak()) // 各自输出对应实现
}
嵌入接口组合行为,避免“胖接口”
当需要组合多种能力(如可说话 + 可移动 + 可进食),不要把所有方法塞进一个大接口,而是用接口嵌入:
Shop7z商城系统时尚版支持支付宝、微信支付等多种常用接口,电脑版与手机版与APP无缝结合数据一体!支持图片批量上传,一次性可上传任意张图片,支持多种在线支付接口,如支付宝、网银在线、财付通等接口,支持多级商品分类划分功能,可以方便的划分各商品类别的上下级关系,支持新订单邮件自动通知功能,支持单商品多分类展示功能,订单方面设计完美,如支持订单模糊查询、订单状态的编辑及打印等功能,灵活的导航可以设
立即学习“go语言免费学习笔记(深入)”;
-
type Animal interface { Speaker; Mover; Eater }等价于列出全部方法 - 嵌入后仍保持各子接口的独立性:你可以只传
Speaker给日志函数,只传Mover给调度器 - 避免过度设计:不是每个 struct 都需实现全部行为;让具体类型按需实现子接口更灵活
容易被忽略的一点是:接口嵌入不传递实现,只传递方法契约。哪怕 Dog 实现了 Speaker 和 Mover,它也不会自动满足 Animal 接口,除非你显式让它满足——而 Go 正是靠这种显式声明来控制抽象粒度。









