# 组合 vs 继承

Golang不支持**继承**，但支持**组合**。怎么理解组合呢？可以拿车来举例，车就是一个轮子、发动机等组件的一个组合。这个模式跟现在流行的前端开发模式有点像，比如React组件化，也是推崇组合，摒弃继承。

#### 实现组合：结构体嵌套

Golang中可以通过结构体嵌套来实现组合。我们拿博客来举个例子，一篇博客包含标题、内容以及作者等信息，这三部分组合在一起形成一篇博客。 我们首先创建一个结构体类型`author`用来表示作者。

```go
package main

import "fmt"

type author struct {
    firstName string
    lastName  string
    bio       string
}

func (a author) fullName() string {
    return fmt.Sprintf("%s %s", a.firstName, a.lastName)
}
```

这里我们首先创建了一个结构体类型`author`，该结构体类型包含三个属性`firstName`、`lastName`以及`bio`。然后我们给该结构体类型绑定了一个方法`fullName`用来获取姓名全称。

下面我们来创建博客结构体类型`post`，并绑定一个方法`details`。

```go
type post struct {
    title   string
    content string
    author
}

func (p post) details() {
    fmt.Println("Title: ", p.title)
    fmt.Println("Content: ", p.content)
    fmt.Println("Author: ", p.author.fullName())
    fmt.Println("Bio: ", p.author.bio)
}
```

这里的结构体类型`post`包含`title`、`content`两个属性，还包含一个匿名嵌套属性`author`。这里包含了一个嵌套结构体`author`，因此我们说`author`是`post`的一个组成部分，或者说`post`由`author`组成。这时我们可以通过`post`来访问`author`的各个属性和方法。 在`details`方法中我们通过结构体类型`post`来访问了`title`、`content`属性字段以及`author`属性的`fullName`方法和`bio`属性。

对于匿名嵌套属性，我们可以简写如下，将匿名字段略去：

```go
func (p post) details() {
    fmt.Println("Title: ", p.title)
    fmt.Println("Content: ", p.content)
    fmt.Println("Author: ", p.fullName())
    fmt.Println("Bio: ", p.bio)
}
```

到这里我们已经定义好了两个结构体类型及其绑定的方法：`author`和`post`，下面写个测试程序来测试下：

```go
package main

import "fmt"

type author struct {
    firstName string
    lastName  string
    bio       string
}

func (a author) fullName() string {
    return fmt.Sprintf("%s %s", a.firstName, a.lastName)
}

type post struct {
    title   string
    content string
    author
}

func (p post) details() {
    fmt.Println("Title: ", p.title)
    fmt.Println("Content: ", p.content)
    fmt.Println("Author: ", p.fullName())
    fmt.Println("Bio: ", p.bio)
}

func main() {
    author1 := author{
        "Naveen",
        "Ramanathan",
        "Golang Enthusiast",
    }

    post1 := post{
        "Inheritance in Go",
        "Go supports composition instead of inheritance",
        author1,
    }

    post1.details()
}
```

&#x20;该程序输出如下：

```
Title:  Inheritance in Go
Content:  Go supports composition instead of inheritance
Author:  Naveen Ramanathan
Bio:  Golang Enthusiast
```

#### 嵌套结构体切片

前面我们看到，一个`post`可以由`title`、`content`和`author`组成，这三个属性都是单个的。但是一个网站(website)肯定是包含多条博客(`post`)的，因此我们可以在`website`结构体类型下面掐套一个`post`结构体切片：

```go
type website struct {
    posts []post
}

func (w website) contents() {
    fmt.Println("Contents of website")
    for _, v := range w.posts {
        v.details()
        fmt.Println()
    }
}
```

这里我们在结构体`website`内部嵌套的是切片类型`[]post`。我们再升级下`main`函数来创建多个`post`结构体变量，并创建一个`website`结构体变量：

```go
package main

import "fmt"

type author struct {
    firstName string
    lastName  string
    bio       string
}

func (a author) fullName() string {
    return fmt.Sprintf("%s %s", a.firstName, a.lastName)
}

type post struct {
    title   string
    content string
    author
}

func (p post) details() {
    fmt.Println("Title: ", p.title)
    fmt.Println("Content: ", p.content)
    fmt.Println("Author: ", p.fullName())
    fmt.Println("Bio: ", p.bio)
}

type website struct {
    posts []post
}

func (w website) contents() {
    fmt.Println("Contents of website")
    for _, v := range w.posts {
        v.details()
        fmt.Println()
    }
}

func main() {
    author1 := author{
        "Naveen",
        "Ramanathan",
        "Golang Enthusiast",
    }
    post1 := post{
        "Inheritance in Go",
        "Go supports composition instead of inheritance",
        author1,
    }
    post2 := post{
        "Struct instead of Classes in Go",
        "Go does not support classes but methods can be added to structs",
        author1,
    }
    post3 := post{
        "Concurrency",
        "Go is a concurrent language and not a parallel one",
        author1,
    }

    w := website{
        posts: []post{post1, post2, post3},
    }
    w.contents()
}
```

这里我们创建了三个结构体`post`类型的变量`post1`，`post2`，`post3`，然后构建了一个切片内嵌到了结构体变量`w`内。

该程序输出如下：

```
Contents of website
Title:  Inheritance in Go
Content:  Go supports composition instead of inheritance
Author:  Naveen Ramanathan
Bio:  Golang Enthusiast

Title:  Struct instead of Classes in Go
Content:  Go does not support classes but methods can be added to structs
Author:  Naveen Ramanathan
Bio:  Golang Enthusiast

Title:  Concurrency
Content:  Go is a concurrent language and not a parallel one
Author:  Naveen Ramanathan
Bio:  Golang Enthusiast
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://sunwenfei.gitbook.io/sunwenfei/golang/golang-ji-chu-jiao-cheng/mian-xiang-dui-xiang-bian-cheng/shi-zu-he-er-bu-shi-ji-cheng.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
