27. 组合取代继承

欢迎来到 Golang 系列教程的第 27 篇。

Go 不支持继承,但它支持组合(Composition)。组合一般定义为“合并在一起”。汽车就是一个关于组合的例子:一辆汽车由车轮、引擎和其他各种部件组合在一起。

通过嵌套结构体进行组合

在 Go 中,通过在结构体内嵌套结构体,可以实现组合。

组合的典型例子就是博客帖子。每一个博客的帖子都有标题、内容和作者信息。使用组合可以很好地表示它们。通过学习本教程后面的内容,我们会知道如何实现组合。

我们首先创建一个 author 结构体。

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 结构体,author 的字段有 firstnamelastnamebio。我们还添加了一个 fullName() 方法,其中 author 作为接收者类型,该方法返回了作者的全名。

下一步我们创建 post 结构体。

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 结构体的字段有 titlecontent。它还有一个嵌套的匿名字段 author。该字段指定 author 组成了 post 结构体。现在 post 可以访问 author 结构体的所有字段和方法。我们同样给 post 结构体添加了 details() 方法,用于打印标题、内容和作者的全名与简介。

一旦结构体内嵌套了一个结构体字段,Go 可以使我们访问其嵌套的字段,好像这些字段属于外部结构体一样。所以上面第 11 行的 p.author.fullName() 可以替换为 p.fullName()。于是,details() 方法可以重写,如下所示:

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

现在,我们的 authorpost 结构体都已准备就绪,我们来创建一个博客帖子来完成这个程序。

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()
}

在 playground 上运行

在上面程序中,main 函数在第 31 行新建了一个 author 结构体变量。而在第 36 行,我们通过嵌套 author1 来创建一个 post。该程序输出:

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

结构体切片的嵌套

我们可以进一步处理这个示例,使用博客帖子的切片来创建一个网站。:smile:

我们首先定义 website 结构体。请在上述代码里的 main 函数中,添加下面的代码,并运行它。

type website struct {  
        []post
}
func (w website) contents() {  
    fmt.Println("Contents of Website\n")
    for _, v := range w.posts {
        v.details()
        fmt.Println()
    }
}

在你添加上述代码后,当你运行程序时,编译器将会报错,如下所示:

main.go:31:9: syntax error: unexpected [, expecting field name or embedded type

这项错误指出了嵌套的结构体切片 []post。错误的原因是结构体不能嵌套一个匿名切片。我们需要一个字段名。所以我们来修复这个错误,让编译器顺利通过。

type website struct {  
        posts []post
}

可以看到,我给帖子的切片 []post 添加了字段名 posts

现在我们来修改主函数,为我们的新网站创建一些帖子吧。

修改后的完整代码如下所示:

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\n")
    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()
}

在 playground 中运行

在上面的主函数中,我们创建了一个作者 author1,以及三个帖子 post1post2post3。我们最后通过嵌套三个帖子,在第 62 行创建了网站 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

本教程到此结束。祝你愉快。

上一教程 – 结构体取代类

若文章对你有帮助,可以点赞或打赏支持我们。发布者:Aurora,转载请注明出处:http://61.174.243.28:13541/AY-knowledg-hub/27-%e7%bb%84%e5%90%88%e5%8f%96%e4%bb%a3%e7%bb%a7%e6%89%bf/

(0)
AuroraAurora站点维系者
上一篇 2023年 12月 5日 下午5:44
下一篇 2023年 12月 5日 下午5:46

相关推荐

  • Pandas安装

    安装 pandas 需要基础环境是 Python,开始前我们假定你已经安装了 Python 和 Pip。 使用 pip 安装 pandas: pip install pandas …

    2023年 5月 16日
  • sendmail

    文章目录sendmail补充说明语法选项 sendmail 著名电子邮件服务器 补充说明 sendmail命令 是一款著名的电子邮件传送代理程序,也就是平常说的电子邮件服务器,它基…

    入门教程 2024年 3月 4日
  • vgscan

    文章目录vgscan补充说明语法选项实例 vgscan 扫描并显示系统中的卷组 补充说明 vgscan命令 查找系统中存在的LVM卷组,并显示找到的卷组列表。vgscan命令仅显示…

    入门教程 2024年 3月 11日
  • cksum

    文章目录cksum补充说明语法选项参数实例 cksum 检查文件的CRC是否正确 补充说明 cksum命令 是检查文件的CRC是否正确,确保文件从一个系统传输到另一个系统的过程中不…

    入门教程 2023年 12月 7日
  • 信道

    文章目录信道什么是信道?声明信道通过信道发送和接收数据发送和接收默认是阻塞的信道的一个例子信道的另一个例子死锁单向信道关闭信道以及使用 range for 遍历信道 信道 上一节:…

    2023年 12月 5日
  • quota

    文章目录quota补充说明语法选项参数实例 quota 显示磁盘已使用的空间与限制 补充说明 quota命令 用于显示用户或者工作组的磁盘配额信息。输出信息包括磁盘使用和配额限制。…

    入门教程 2024年 3月 1日
  • Git 安装配置

    在使用Git前我们需要先安装 Git。Git 目前支持 Linux/Unix、Solaris、Mac和 Windows 平台上运行。 Git 各平台安装包下载地址为:http://…

    2024年 4月 30日
  • chfn

    文章目录chfn补充说明语法选项参数实例 chfn 用来改变finger命令显示的信息 补充说明 chfn命令 用来改变finger命令显示的信息。这些信息都存放在/etc目录里的…

    入门教程 2023年 12月 7日
  • pkexec

    文章目录pkexec补充说明语法选项返回值示例参考资料 pkexec 以其他用户身份执行命令 补充说明 pkexec 允许授权用户以另一个用户的身份执行 PROGRAM。如果未指定…

    入门教程 2024年 3月 1日
  • ethtool

    文章目录ethtool补充说明语法选项数据来源实例 ethtool 显示或修改以太网卡的配置信息 补充说明 ethtool命令用于获取以太网卡的配置信息,或者修改这些配置。这个命令…

    入门教程 2023年 12月 14日
Translate »