Go 接口(interface)
🧱 一、什么是 interface?
interface
是 Go 语言中实现 多态(polymorphism) 的核心机制。
一句话解释:接口就是一种行为的抽象,它定义了一组方法,而不是具体的实现。任何类型只要实现了接口定义的方法,就被视为实现了该接口。
📐 二、interface 的基本语法
type Speaker interface { Speak() }
上面这个接口定义了一个 Speak()
方法,任何类型只要有 Speak()
方法,就自动实现了 Speaker
接口。
✅ 示例一:简单实现
type LiuBei struct{} type CaoCao struct{} func (l LiuBei) Speak() { fmt.Println("我是刘备,仁德为本") } func (c CaoCao) Speak() { fmt.Println("宁教我负天下人,休教天下人负我") } func introduce(s Speaker) { s.Speak() }
使用:
introduce(LiuBei{}) // 输出:我是刘备,仁德为本 introduce(CaoCao{}) // 输出:宁教我负天下人,休教天下人负我
🧠 三、interface 的本质(非常重要)
interface 是什么?
从底层看,interface
本质上是一个二元结构,包含:
-
type
:实际数据的类型 -
value
:实际数据的值
type iface struct { tab *itab // 类型信息 data unsafe.Pointer // 实际数据 }
所以你传的是值,底层是“值 + 类型”,用的是动态分发。
📦 四、隐式实现 & 解耦设计
Go 语言的接口是隐式实现的,即:不需要显式声明“我实现了哪个接口”,只要方法签名对得上,就自动实现接口。
这一点在解耦方面非常强大,比如你可以轻松替换不同的模块。
🧰 五、接口类型变量
var s Speaker
这是一个接口变量,可以接收任何实现了 Speak()
方法的值。
s = LiuBei{} s.Speak() // 输出:我是刘备,仁德为本
🛠 六、空接口 interface{}
interface{}
空接口没有任何方法,所有类型都实现了它,所以可以表示任意值。
使用场景:
-
fmt.Println(...)
-
map[string]interface{}
-
json.Unmarshal
时的interface{}
func show(v interface{}) { fmt.Println("值是:", v) }
🧰 七、类型断言(Type Assertion)
把接口变量还原成它的具体类型:
var s Speaker = LiuBei{} liu, ok := s.(LiuBei) if ok { fmt.Println("转换成功:", liu) }
也可用于空接口:
var x interface{} = "Hello" str := x.(string) // 安全:类型匹配 num := x.(int) // 会 panic:类型不匹配
建议使用断言+判断:
if str, ok := x.(string); ok { fmt.Println("是字符串", str) }
🧪 八、类型 switch
func testType(v interface{}) { switch value := v.(type) { case string: fmt.Println("字符串:", value) case int: fmt.Println("整数:", value) default: fmt.Println("未知类型") } }
🔁 九、接口组合(组合多个行为)
type Reader interface { Read(p []byte) (n int, err error) } type Writer interface { Write(p []byte) (n int, err error) } type ReadWriter interface { Reader Writer }
ReadWriter
就是组合了 Reader + Writer
两个接口,Go 中所有接口都可以像这样组合。
🎮 十、用三国人物设计一组接口
type Warrior interface { Attack() } type Strategist interface { Plan() } type Commander interface { Warrior Strategist }
定义几个人物:
type GuanYu struct{} func (g GuanYu) Attack() { fmt.Println("关羽奋勇杀敌") } type ZhugeLiang struct{} func (z ZhugeLiang) Plan() { fmt.Println("诸葛亮妙计安天下") } type LiuBei struct{} func (l LiuBei) Attack() { fmt.Println("刘备激励士气") } func (l LiuBei) Plan() { fmt.Println("刘备善用人心") }
使用:
func LeadBattle(c Commander) { c.Plan() c.Attack() } LeadBattle(LiuBei{})
📏 十一、interface 使用建议
建议 | 原因 |
---|---|
尽量面向接口编程 | 实现解耦,便于测试 |
接口要小而精 | Go 强调“小接口” |
接口定义应由使用者定义 | 不由实现者来决定(反转) |
使用空接口时一定要断言类型 | 保证类型安全 |
使用结构体嵌套组合接口 | 更灵活、更可扩展 |
✅ 十二、总结
概念 | 说明 |
---|---|
interface | 行为抽象,不关心数据类型 |
隐式实现 | 只要方法匹配就自动实现 |
空接口 | 万能类型 |
类型断言 | 从接口变量中取出原始值 |
接口组合 | 将多个接口拼合为一体 |
👉 立即点击链接,开启你的全栈开发之路:Golang全栈开发完整课程