目录
Please enable Javascript to view the contents

Go Struct 组合与匿名字段

 ·  ☕ 2 分钟

重要

Go 没有继承,用结构体嵌套(组合)+ 接口实现代码复用。匿名字段会触发字段和方法提升——被嵌套结构体的字段和方法自动提升为外部结构体的一部分。

1. 组合 vs 继承

Go 组合传统 OOP 继承
关系has-ais-a
方式结构体嵌套extends 关键字
多态接口(鸭子类型)父类引用指向子类对象
访问控制首字母大小写public/protected/private
多级层级扁平组合,无层级多层继承链

Go 的设计哲学是组合优于继承(composition over inheritance)。没有父子类概念,只有组合关系。

2. 匿名字段与字段提升

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
type Person struct {
    Name string
    Age  int
}

type Employee struct {
    Person        // 匿名字段——Person 的所有字段提升为 Employee 的字段
    Company string
}

e := Employee{
    Person:  Person{Name: "Alice", Age: 30},
    Company: "ACME",
}

fmt.Println(e.Name)   // "Alice"(字段提升,无需 e.Person.Name)
fmt.Println(e.Age)    // 30

提升规则:

提升内容说明
字段被嵌套结构体的所有导出和非导出字段
方法被嵌套结构体的所有方法
冲突同名时外部优先(覆盖);多个内部同名 → 编译错误

3. 方法覆盖(非重写)

如果外部结构体定义了与内部同名的方法,外部方法会覆盖内部方法。但无法通过外部结构体直接调用被覆盖的内部方法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
func (p Person) Greet() string {
    return "Hi, I'm " + p.Name
}

func (e Employee) Greet() string {
    // 覆盖 Person.Greet()
    return e.Person.Greet() + " from " + e.Company  // 通过内部字段名显式调用
}

e.Greet()           // "Hi, I'm Alice from ACME"
e.Person.Greet()    // "Hi, I'm Alice"(显式调用内部方法)

不同于 OOP 的 super——Go 中没有隐式的父级调用语法,必须通过内部字段名显式引用。

4. 接口与多态

Go 通过接口实现多态。任何类型只要实现了接口的所有方法,就自动满足该接口(鸭子类型)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
type Greeter interface {
    Greet() string
}

func SayHello(g Greeter) {
    fmt.Println(g.Greet())
}

p := Person{Name: "Bob"}
e := Employee{Person: Person{Name: "Alice"}, Company: "ACME"}

SayHello(p)  // Bob 实现 Greeter
SayHello(e)  // Employee 也实现 Greeter
传统 OOPGo
显式声明 implements隐式满足——实现所有方法即可
类型间有继承层级类型间无层级关系
编译时检查父子关系编译时检查方法签名匹配

5. 总结

  1. Go 无继承——用结构体嵌套(组合)+ 接口实现代码复用;
  2. 匿名字段触发字段/方法提升,同名时外部覆盖内部;
  3. 多态通过接口隐式满足实现,无需显式声明;
  4. 无需 super 语法——通过内部字段名显式调用被覆盖的方法。

6. 参考

分享

Hex
作者
Hex
CloudNative Developer