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
七、小结
特性 | 描述 |
匿名字段 | 嵌入类型,无需字段名,字段名自动为类型名 |
方法提升 | 嵌入类型的方法会自动“继承” |
字段提升 | 可直接访问嵌入类型的字段 |
字段冲突优先级 | 外层结构体字段优先 |
支持指针/值嵌入 | 嵌入字段可为值或指针类型,方法访问自动解引用 |
多重组合 | 可以嵌套多个匿名字段,支持结构体“组合式编程” |