Go的多态仅通过接口与隐式实现达成:类型只要实现接口所有方法即自动满足,无需显式声明;接收者类型(值或指针)决定实现归属,影响赋值兼容性;interface{}需谨慎类型断言,推荐带ok检查;多态基于行为契约而非继承关系,强调组合与小接口设计。

Go 里没有 class、inheritance、virtual function 这些词,所谓“多态”只有一条路:接口(interface)+ 隐式实现。只要类型实现了接口所有方法,它就自动是那个接口类型——不用 implements,也不用 override,写对了就能用,写错了编译器立刻报。
为什么 func (s S) Method() 和 func (s *S) Method() 不能混用?
这是最常踩的坑:接收者类型决定了谁能“拥有”这个实现。
- 如果接口方法签名要求指针接收者(比如
func (s *S) Put(int)),那只有*S类型能赋值给该接口,S值类型不行 - 反过来,如果所有方法都是值接收者,
S和*S都能赋值——但注意:*S调用时会自动解引用,S调用时会复制一份 - 错误示例:
cannot use mb (type MyBook) as type IBook in assignment: MyBook does not implement IBook (ChangeBookName method has pointer receiver)
interface{} 不是万能转发器,类型断言要小心
空接口能存任何值,但取出来时必须知道它原本是什么类型,否则运行时报 panic。
- 安全写法用
if v, ok := x.(MyType); ok,ok为 false 表示类型不匹配 - 用
switch t := x.(type)可以批量处理多种可能类型,比一串if-else清晰 - 直接写
x.(MyType)(没加ok)一旦类型不对,程序立刻崩溃
多态不是靠继承树,而是靠“行为契约”
Go 的多态不关心类型有没有父子关系,只看它能不能做某件事。比如 io.Reader 接口只要求 Read([]byte) (int, error),os.File、bytes.Buffer、net.Conn 互不相干,但都能当 io.Reader 用。
立即学习“go语言免费学习笔记(深入)”;
- 定义接口时,方法名和签名就是契约;实现时,你用什么结构体、嵌套几层都不重要
- 组合优于继承:想复用行为?嵌入一个字段就行,比如
type MyWriter struct { io.Writer },再补几个自己的方法,它自然也满足io.Writer - 别试图模拟 Java/C++ 的“父类引用指向子类对象”——Go 里只有“变量是接口类型,背后值是任意实现者”
真正难的不是写接口,而是判断哪些行为该抽象成接口、哪些该留在具体类型里。过度抽象会让调用方困惑,抽象不足又失去多态价值。接口越小越好,方法越少越容易实现,也越容易被复用。


















