Go 没有传统的面向对象继承机制,但它通过“匿名字段(embedding)”实现了类似继承的组合方式,使得一个类型可以“继承”另一个类型的字段和方法。
一、什么是匿名字段
匿名字段就是在结构体中嵌套一个类型而不显式命名字段名。该字段的名字默认就是其类型名。
示例:
type Person struct {
Name string
Age int
}
type Student struct {
Person // 匿名字段,嵌入 Person
SchoolName string
}
这里的 Student
类型“组合”了 Person
类型,它自动获得了 Person
的字段和方法访问权限。
二、使用嵌入字段
s := Student{
Person: Person{Name: "Alice", Age: 20},
SchoolName: "Go大学",
}
fmt.Println(s.Name) // 自动访问嵌入字段的字段:Alice
fmt.Println(s.Age) // 20
实际上等价于:
fmt.Println(s.Person.Name)
三、方法提升(Method Promotion)
如果嵌入的类型定义了方法,外层类型会自动拥有这些方法。
func (p Person) SayHi() {
fmt.Println("Hi, I'm", p.Name)
}
s := Student{Person: Person{Name: "Tom"}}
s.SayHi() // 自动继承 Person 的方法
四、指针匿名字段
也可以嵌入指针类型:
type Teacher struct {
*Person // 匿名嵌入指针
Subject string
}
只要嵌入类型是指针或值,Go 都会自动处理方法调用的自动解引用。
五、字段名冲突的情况
如果外部结构体和匿名字段中存在同名字段或方法,优先使用外层结构体的成员。
type Person struct {
Name string
}
type Employee struct {
Person
Name string // 会隐藏 Person.Name
}
e := Employee{
Person: Person{Name: "Tom"},
Name: "Jerry",
}
fmt.Println(e.Name) // Jerry
fmt.Println(e.Person.Name) // Tom
六、嵌套多个匿名字段
可以同时嵌入多个匿名字段,实现多重组合:
type Contact struct {
Email string
Phone string
}
type Profile struct {
Person
Contact
}
调用:
p := Profile{
Person: Person{Name: "Lily", Age: 28},
Contact: Contact{Email: "lily@example.com", Phone: "123456"},
}
fmt.Println(p.Email) // 直接访问 Contact.Email
七、小结
特性 | 描述 |
匿名字段 | 嵌入类型,无需字段名,字段名自动为类型名 |
方法提升 | 嵌入类型的方法会自动“继承” |
字段提升 | 可直接访问嵌入类型的字段 |
字段冲突优先级 | 外层结构体字段优先 |
支持指针/值嵌入 | 嵌入字段可为值或指针类型,方法访问自动解引用 |
多重组合 | 可以嵌套多个匿名字段,支持结构体“组合式编程” |