本文是《Go系列教程》的第二十三篇文章。

Go本身不支持继承,但是它支持组合。组合的通常定义是:“放置在一起”。组合的一个例子就是汽车。一个汽车由轮子、引擎、各种不同的部分组成。

内嵌结构体实现组合

在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结构体,该结构体有字段:firstName、lastName、bio。同时,我们还添加了一个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结构体有字段:title,content。同时,它还有一个匿名字段 author。该字段表明,post结构体是由author结构体一块组成的。此时,post结构体就可以访问author结构体的所有字段和方法。另外,我们还在post结构体中添加了一个detail()方法。此方法会打印tile,content,fullName以及author的bio。

当一个结构体字段嵌入在另一个结构体中时,Go允许我们直接访问这个内嵌的字段就好像它是外层结构体的一部分一样。这也就意味着,p.author.fullName可以使用p.fullName代替。因此detail()方法可以重写如下:

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结构体了。我们来完成这个程序。

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

程序的输出如下:

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

内嵌结构体的分片

我们进一步扩展上面的例子,我们现在使用一个博客分片来创建一个网站。

我们先定义一个website结构体,我们在main函数的上面添加如下代码:

type website struct {
        []post
}
func (w website) contents() {
    fmt.Println("Contents of Websiten")
    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分片[]post添加了一个字段名称。

现在,我们来修改main函数,并为我们的新网址添加几个博客文章。

完整的程序如下:

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

在上面的程序中,我们创建了一个作者author1,以及3个博客:post1、post2、post3。最后,通过内嵌3个博客,我们创建了一个网站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

感谢您的阅读,请留下您珍贵的反馈和评论。Have a good Day!

备注
本文系翻译之作原文博客地址

文章来源于互联网,如有雷同请联系站长删除:Go教程第二十三篇: Go中的面向对象:组合而不是继承

发表评论