24_嵌入与组合复用
理解匿名字段的方法提升与方法集,避免误把嵌入当类继承。
Go 基础专题 24:嵌入与组合复用
学习目标:理解匿名字段的方法提升与方法集,避免误把嵌入当类继承。
核心知识
结构体可嵌入另一个类型:type Admin struct { User; Level int }。若 User 有 Name 字段,可写 admin.Name,它实际经由 admin.User.Name 访问。方法也可能被提升,但发生同名冲突时需要显式选择路径。嵌入并不会使 Admin 成为 User 的子类型。
package main
import "fmt"
type User struct { Name string }
func (u User) Label() string { return u.Name }
type Admin struct {
User
Level int
}
func main() {
admin := Admin{User: User{Name: "Ada"}, Level: 2}
fmt.Println(admin.Label(), admin.User.Name)
}
若一个类型只需要另一个类型的部分能力,普通命名字段有时比嵌入更明确。嵌入指针类型时要确保指针已初始化;零值嵌入指针为 nil,调用依赖其值的方法可能出错。接口嵌入可组合多个方法约束。
复用不必形成深层对象层级。Go 更常通过小接口、组合和普通函数组织功能。设计时先描述数据与行为的边界,再决定是否嵌入。
逐步理解
嵌入字段让 admin.Label() 可调用内层方法,但 Admin 仍不能直接赋给需要 User 的变量;要显式使用 admin.User。若外层也定义 Label,外层方法优先,内层方法仍可通过字段路径访问。组合的好处是复用实现同时保持对象关系清晰,避免深继承层次。
动手练习
练习:给 Admin 添加自己的 Label,打印等级和姓名。答案要点:同名方法会覆盖提升的方法,但 admin.User.Label() 仍可调用。