结构体嵌套 #

一、嵌套概述 #

Go通过结构体嵌套实现组合,支持匿名字段和字段提升。

二、命名嵌入 #

2.1 基本用法 #

go
type Address struct {
    City    string
    Country string
}

type Person struct {
    Name    string
    Address Address
}

p := Person{
    Name: "Alice",
    Address: Address{
        City:    "Beijing",
        Country: "China",
    },
}

fmt.Println(p.Address.City)  // Beijing

2.2 访问方式 #

go
p.Address.City = "Shanghai"
fmt.Println(p.Address.City)

三、匿名嵌入 #

3.1 基本用法 #

go
type Person struct {
    Name string
    Address  // 匿名嵌入
}

p := Person{
    Name: "Alice",
    Address: Address{
        City: "Beijing",
    },
}

fmt.Println(p.City)  // Beijing(字段提升)
fmt.Println(p.Address.City)  // Beijing

3.2 字段提升 #

匿名字段的字段被提升到外层:

go
type Inner struct {
    X int
}

type Outer struct {
    Inner
    Y int
}

o := Outer{Inner: Inner{X: 10}, Y: 20}
fmt.Println(o.X)      // 10(提升)
fmt.Println(o.Inner.X) // 10
fmt.Println(o.Y)      // 20

3.3 内置类型嵌入 #

go
type MySlice []int

func (s MySlice) Sum() int {
    sum := 0
    for _, v := range s {
        sum += v
    }
    return sum
}

type Data struct {
    MySlice
}

d := Data{MySlice: MySlice{1, 2, 3}}
fmt.Println(d.Sum())     // 3
fmt.Println(d.MySlice.Sum())  // 3

四、方法继承 #

4.1 继承方法 #

go
type Animal struct {
    Name string
}

func (a Animal) Speak() {
    fmt.Println("Some sound")
}

type Dog struct {
    Animal
}

func main() {
    d := Dog{Animal{Name: "Buddy"}}
    d.Speak()  // Some sound
}

4.2 方法重写 #

go
func (d Dog) Speak() {
    fmt.Println("Woof!")
}

func main() {
    d := Dog{Animal{Name: "Buddy"}}
    d.Speak()          // Woof!
    d.Animal.Speak()   // Some sound
}

4.3 方法链 #

go
type Base struct{}

func (b Base) Method1() {
    fmt.Println("Base.Method1")
}

type Middle struct {
    Base
}

func (m Middle) Method2() {
    fmt.Println("Middle.Method2")
}

type Derived struct {
    Middle
}

func main() {
    d := Derived{}
    d.Method1()  // Base.Method1
    d.Method2()  // Middle.Method2
}

五、字段冲突 #

5.1 同名字段 #

go
type A struct {
    X int
}

type B struct {
    X int
}

type C struct {
    A
    B
}

c := C{A: A{X: 1}, B: B{X: 2}}
// fmt.Println(c.X)  // 错误:歧义
fmt.Println(c.A.X)  // 1
fmt.Println(c.B.X)  // 2

5.2 外层覆盖内层 #

go
type Inner struct {
    X int
}

type Outer struct {
    Inner
    X int  // 覆盖Inner.X
}

o := Outer{Inner: Inner{X: 1}, X: 2}
fmt.Println(o.X)      // 2(外层)
fmt.Println(o.Inner.X) // 1

六、指针嵌入 #

6.1 指针嵌入 #

go
type Person struct {
    Name string
    Address *Address
}

p := Person{
    Name: "Alice",
    Address: &Address{
        City: "Beijing",
    },
}

fmt.Println(p.City)  // Beijing

6.2 nil检查 #

go
type Person struct {
    Address *Address
}

func (p Person) GetCity() string {
    if p.Address == nil {
        return "Unknown"
    }
    return p.Address.City
}

七、组合模式 #

7.1 组合优于继承 #

Go推荐使用组合而非继承:

go
type Writer interface {
    Write([]byte) (int, error)
}

type Reader interface {
    Read([]byte) (int, error)
}

type ReadWriter struct {
    Reader
    Writer
}

7.2 实际应用 #

go
type Logger struct {
    prefix string
}

func (l Logger) Log(msg string) {
    fmt.Printf("[%s] %s\n", l.prefix, msg)
}

type Service struct {
    Logger
    name string
}

func main() {
    s := Service{
        Logger: Logger{prefix: "INFO"},
        name:   "MyService",
    }
    s.Log("Service started")
}

八、嵌入接口 #

8.1 基本用法 #

go
type Reader interface {
    Read() string
}

type Writer interface {
    Write(string)
}

type ReadWriter interface {
    Reader
    Writer
}

8.2 结构体嵌入接口 #

go
type Handler struct {
    http.Handler
}

func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Println("Before")
    h.Handler.ServeHTTP(w, r)
    fmt.Println("After")
}

九、实际应用 #

9.1 装饰器模式 #

go
type DataSource interface {
    Read() string
}

type FileSource struct {
    content string
}

func (f *FileSource) Read() string {
    return f.content
}

type CachedSource struct {
    DataSource
    cache string
}

func (c *CachedSource) Read() string {
    if c.cache == "" {
        c.cache = c.DataSource.Read()
    }
    return c.cache
}

9.2 中间件模式 #

go
type Handler struct {
    next http.Handler
}

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Println("Middleware before")
    h.next.ServeHTTP(w, r)
    fmt.Println("Middleware after")
}

9.3 混入模式 #

go
type Timestamp struct {
    CreatedAt time.Time
    UpdatedAt time.Time
}

func (t *Timestamp) Touch() {
    t.UpdatedAt = time.Now()
}

type User struct {
    ID   int
    Name string
    Timestamp
}

type Article struct {
    ID    int
    Title string
    Timestamp
}

十、最佳实践 #

10.1 优先组合 #

go
// 好:组合
type Service struct {
    Logger
    DB
}

// 避免:深层嵌套
type A struct { B }
type B struct { C }
type C struct { D }

10.2 避免过度嵌套 #

go
// 简单清晰
type User struct {
    Name    string
    Address Address
}

// 过度嵌套
type User struct {
    Profile struct {
        Basic struct {
            Name string
        }
    }
}

10.3 明确字段来源 #

go
type Person struct {
    Name string
    Address
}

p := Person{}
p.City = "Beijing"      // 清晰
p.Address.City = "Beijing"  // 更明确

十一、总结 #

嵌套要点:

特性 说明
命名嵌入 显式访问
匿名嵌入 字段提升
方法继承 继承嵌入类型的方法
字段冲突 需要显式指定

关键点:

  1. 组合优于继承:Go推荐组合
  2. 字段提升:匿名字段提升到外层
  3. 方法继承:继承嵌入类型的方法
  4. 冲突处理:同名字段需要显式指定
  5. 指针嵌入:注意nil检查

准备好学习结构体标签了吗?让我们进入下一章!

最后更新:2026-03-26