
接口不关心你是谁,只关心你会干什么。它定义了一组行为规范。
package main
import "fmt"
// 定义一个"才子"接口
type Talent interface {
Perform() string // 只要会"表演"并返回字符串,就是才子
}
在 Java 等语言里,你得大喊“我实现了这个接口”(implements)。但在 Go 语言里,只要你默默地做到了接口要求的事,你就是它的人!
这叫鸭子类型 (Duck Typing):如果它走起路来像鸭子,叫起来像鸭子,那它就是鸭子。
type Tang struct {
Poem string
}
// 唐伯虎实现了 Perform 方法
func (t Tang) Perform() string {
return "桃花坞里桃花庵... " + t.Poem
}
type Qiuxiang struct {
Smile string
}
// 秋香也实现了 Perform 方法
func (q Qiuxiang) Perform() string {
return "回眸一笑百媚生... " + q.Smile
}

Perform,那我也是 Talent 接口的一员咯?
现在我们可以写一个函数,接待所有“才子”。
// 接收 Talent 接口类型的参数
func ShowTime(t Talent) {
fmt.Println("表演开始:", t.Perform())
}
func main() {
tang := Tang{Poem: "别人笑我太疯癫"}
qiuxiang := Qiuxiang{Smile: "三笑留情"}
// 只要实现了接口,就能传进去
ShowTime(tang) // 输出:桃花坞里桃花庵... 别人笑我太疯癫
ShowTime(qiuxiang) // 输出:回眸一笑百媚生... 三笑留情
}
这是新手最容易掉的坑!如果方法是用指针接收者实现的,那么只有指针才算实现了接口。
type Painter interface {
Draw()
}
type Scholar struct {}
// 注意:这里用的是指针接收者 (s *Scholar)
func (s *Scholar) Draw() {
fmt.Println("画了一只小鸡吃米图")
}
func main() {
var p Painter
s := Scholar{}
// p = s // ❌ 报错!Scholar 没有实现 Painter (是 *Scholar 实现的)
p = &s // ✅ 正确!*Scholar 实现了 Painter
p.Draw()
}
接口变量在内存里其实有两部分:
*Tang)。nil 或 0x12345)。只有当 Type 和 Value 都是 nil 时,接口才是 nil!
func main() {
var tang *Tang = nil // 唐伯虎还没出门,是空的 (nil)
// 把这个空指针给接口
var i Talent = tang
// 问:i 是 nil 吗?
if i == nil {
fmt.Println("接口是空的")
} else {
fmt.Println("接口不是空的!(虽然唐伯虎不在,但名牌还在)")
}
// 输出:接口不是空的!
// 为什么?
// i 的结构:(Type: *Tang, Value: nil)
// 只要 Type 不为空,i 就不是 nil。
}
nil 指针赋值给接口,除非你真的想让它“不为空”。
接口也可以像结构体一样组合。比如“江南四大才子”不仅要会“表演”,还要会“喝酒”。
type Performer interface {
Perform()
}
type Drinker interface {
Drink()
}
// 四大才子接口:集大成者
type TopTalent interface {
Performer // 嵌入表演接口
Drinker // 嵌入喝酒接口
}
// 只有同时学会这两个技能,才配叫 TopTalent
如果一个接口里面什么方法都没有,那岂不是所有人都实现了它?
没错!interface{} (现在 Go 1.18+ 也叫 any) 可以接收任何类型的值。就像一个万能收纳箱。
func PrintAnything(v interface{}) {
fmt.Printf("你给了我一个: %v\n", v)
}
func main() {
PrintAnything("秋香") // string
PrintAnything(9527) // int
PrintAnything(true) // bool
}
祝枝山也要参加比赛,他的才艺是“神鸟凤凰图”。请帮他实现 Talent 接口。
package main
import "fmt"
type Talent interface {
Perform()
}
type Zhu struct {}
// 填空:实现接口方法
func (z Zhu) ______() {
fmt.Println("这是小鸡吃米图!")
}
func main() {
var t Talent = Zhu{}
t.Perform()
}
任务: 填补方法名。
答案: Perform
解析: 接口定义了什么方法名,你就得实现什么方法名。