二十六.golang的组合
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 的字段有 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。该字段指定 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) }
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 Website\n") for _, v := range w.posts { v.details() fmt.Println() } }
在你添加上述代码后,当你运行程序时,编译器将会报错,如下所示:
main.go:31:9: syntax error: unexpected [, expecting field name or embedded type
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() }
在上面的主函数中,我们创建了一个作者 author1,以及三个帖子 post1、post2 和 post3。我们最后通过嵌套三个帖子,在第 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