Go 继承

Go 没有继承:用嵌入做组合、用接口做多态、用委托做复用。

Intermediate
Key PointsGo 用「组合优于继承」:嵌入得到字段和方法的提升,接口得到多态。

先说结论

Go has no classes, no inheritance, no virtual functions, no extends. It offers two substitutes: embedding (reuse fields and methods) and interfaces (polymorphism). People arriving from Java or C++ look for inheritance first, then discover composition.

嵌入

Go
type Animal struct {
	Name string
}

func (a Animal) Speak() string {
	return a.Name + " 发出声音"
}

func (a Animal) Move() string {
	return a.Name + " 移动"
}

type Dog struct {
	Animal            // 嵌入
	Breed  string
}

d := Dog{Animal: Animal{Name: "旺财"}, Breed: "柴犬"}
fmt.Println(d.Name)          // 提升的字段
fmt.Println(d.Speak())       // 提升的方法
fmt.Println(d.Move())
Output
旺财
旺财 发出声音
旺财 移动

覆盖(不是重写)

Go
// Dog 自己定义 Speak,遮蔽 Animal 的
func (d Dog) Speak() string {
	return d.Name + " 汪汪叫"
}

d := Dog{Animal: Animal{Name: "旺财"}}
fmt.Println(d.Speak())               // Dog 的版本
fmt.Println(d.Animal.Speak())        // 显式调用被遮蔽的
Output
旺财 汪汪叫
旺财 发出声音
This is not polymorphism. Dog.Speak does not affect calls to Speak inside Animal.Move — Go has no vtable. To dispatch, pass an interface into Move.

用接口实现真正的多态

Go
type Speaker interface {
	Speak() string
}

func announce(s Speaker) {
	fmt.Println("广播:", s.Speak())
}

type Cat struct{ Name string }

func (c Cat) Speak() string { return c.Name + " 喵喵叫" }

announce(Dog{Animal{Name: "旺财"}, "柴犬"})
announce(Cat{Name: "咪咪"})
Output
广播: 旺财 汪汪叫
广播: 咪咪 喵喵叫

Interfaces are Go's polymorphism. announce depends on exactly one method, so any type implementing it works — far more flexible than a class hierarchy, and no upfront design needed.

嵌入接口

Go
type Reader interface{ Read(p []byte) (int, error) }
type Closer interface{ Close() error }

// 接口可以嵌入接口
type ReadCloser interface {
	Reader
	Closer
}

// 结构体也可以嵌入接口,用来「部分实现」或做 mock
type MockReadCloser struct {
	Reader                  // 嵌入接口,未实现的方法会 panic
}

func (m MockReadCloser) Close() error { return nil }

Embedding an interface in a struct is a mocking trick: implement only the methods under test and leave the rest to a nil interface — calling them panics, which reminds you they are unstubbed.

组合优于继承的实例

Go
// 继承的写法会得到「正方形是不是矩形」这类问题
// Go 的写法:各自独立,共享能力用接口

type Logger interface{ Log(msg string) }

type Service struct {
	Logger                 // 注入日志能力
	DB     *sql.DB
}

func (s *Service) Create(name string) error {
	s.Log("创建 " + name)
	return nil
}
NeedGo way
复用字段嵌入结构体
复用方法嵌入 + 委托
多态接口
扩展第三方类型包装(组合)+ 方法
模板方法模式把函数当参数传
Want to add methods to a type from another package? Wrap it: type MyTime struct{ time.Time } and add your own methods. That is Go's standard "extension".

Friends & Partners