Go 面向对象:匿名字段核心知识点
Go 语言没有传统的类继承,而是通过匿名字段(组合)实现代码复用、类似继承的效果,是 Go 面向对象的核心特性。
一、Go 面向对象三大特性(结合匿名字段)
- 继承:通过匿名字段(组合)实现,复用已有结构体的成员和方法
- 封装:隐藏内部实现,只对外提供功能,通过结构体 + 匿名字段实现
- 多态:通过接口实现
二、匿名组合(匿名字段)
1. 什么是匿名字段?
定义结构体时,只写类型,不写字段名,这个字段就是匿名字段。作用:直接复用另一个结构体的所有成员(字段 + 方法)。
2. 基础语法示例
go
package main import "fmt" // 父结构体 type Person struct { name string // 姓名 sex byte // 性别 age int // 年龄 } // 子结构体:匿名字段继承 Person type Student struct { Person // 匿名字段,继承Person的所有成员 id int addr string }三、匿名字段初始化(重点)
1. 完整初始化(必须指定匿名字段结构体名)
go
func main() { // 方式1:var 定义 var s1 Student = Student{Person{"mike", 'm', 18}, 1, "bj"} fmt.Println("s1 = ", s1) // 方式2:自动推导类型 s2 := Student{Person{"mike", 'm', 18}, 1, "bj"} fmt.Printf("s2 = %v\n", s2) }2. 指定成员初始化
go
func main() { // 只初始化 id,其他字段默认零值 s3 := Student{id: 1} fmt.Printf("s3 = %+v\n", s3) // 显式初始化匿名字段的部分成员 s4 := Student{Person: Person{name: "mike"}, id: 1} fmt.Printf("s4 = %+v\n", s4) }错误写法(必须记住)
go
// 编译失败!匿名字段不能直接展开赋值 // s5 := Student{"mike", 'm', 18, 1, "bj"}规则:初始化匿名字段时,必须带上外层结构体名,否则编译报错。
四、成员操作
匿名字段继承的成员,可以直接访问 / 赋值,和结构体自身成员一样。
go
func main() { s1 := Student{Person{"mike", 'm', 18}, 1, "bj"} // 直接访问继承的字段 fmt.Println(s1.name, s1.sex, s1.age, s1.id, s1.addr) // 直接赋值 s1.name = "yoyo" s1.age = 16 fmt.Println(s1) }五、同名字段处理(就近原则)
如果子结构体和匿名字段结构体有同名成员:
- 默认:就近原则→ 优先使用子结构体自己的成员
- 显式调用→
子结构体.匿名字段类型.字段名
go
type Person struct { name string } type Student struct { Person // 匿名字段 name string // 同名字段 } func main() { var s Student // 就近原则:操作 Student 的 name s.name = "student" // 显式调用:操作 Person 的 name s.Person.name = "person" fmt.Printf("s.name = %s\n", s.name) // 输出 student fmt.Printf("s.Person.name = %s\n", s.Person.name) // 输出 person }六、非结构体匿名字段
匿名字段可以是:基本类型、自定义类型,不只是结构体。
go
// 自定义类型 type mystr string type Student struct { Person // 结构体匿名字段 int // 基本类型匿名字段 mystr // 自定义类型匿名字段 } func main() { s := Student{int: 100, mystr: "hello"} fmt.Println(s.int, s.mystr) }七、结构体指针作为匿名字段
使用指针类型作为匿名字段,节省内存,传递引用。
go
type Student struct { *Person // 指针匿名字段 id int addr string } func main() { // 方式1:直接初始化 s1 := Student{&Person{"mike", 'm', 18}, 666, "bj"} fmt.Println(s1.name) // 直接访问,自动解引用 // 方式2:new 分配空间 var s2 Student s2.Person = new(Person) // 分配内存 s2.name = "yoyo" s2.sex = 'm' s2.age = 18 s2.id = 222 s2.addr = "sz" fmt.Println(s2) }八、核心总结
- Go 没有继承,只有匿名字段(组合),实现代码复用
- 初始化匿名字段必须写结构体类型名,否则编译失败
- 同名字段遵循就近原则,显式调用需指定匿名字段类型
- 支持:结构体、基本类型、指针类型作为匿名字段
- 是 Go 实现类似继承的唯一方式