Go 不支持继承,但是它支持组合。组合的一般定义是“放在一起”。组合的一个例子是汽车。汽车是由轮子、发动机和其他各种部件组成的。

通过嵌入结构来组合

组合可以通过将一个结构类型嵌入到另一个结构类型中来实现。

一篇博客文章就是一个很好的组合例子。每个博客文章都有标题、内容和作者信息。这可以用组合完美地表示。在本教程的后续步骤中,我们将学习如何实现这一点。

让我们首先创建 author 结构。

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. type author struct {
  6. firstName string
  7. lastName string
  8. bio string
  9. }
  10. func (a author) fullName() string {
  11. return fmt.Sprintf("%s %s", a.firstName, a.lastName)
  12. }

在上面的代码片段中,我们创建了一个包含 firstNamelastNamebio 字段的 author 结构。我们还添加了一个方法 fullName()author 为接收者类型,返回作者的全名。

下一步是创建 post 结构。

  1. type post struct {
  2. title string
  3. content string
  4. author
  5. }
  6. func (p post) details() {
  7. fmt.Println("Title: ", p.title)
  8. fmt.Println("Content: ", p.content)
  9. fmt.Println("Author: ", p.author.fullName())
  10. fmt.Println("Bio: ", p.author.bio)
  11. }

post 结构具有字段 titlecontent。它还有一个嵌入式匿名字段 author。该字段表示 post 结构由 author 组成。现在 post struct 可以访问 author 结构的所有字段和方法。我们还在 post 结构中添加了 details() 方法,用于输出作者的title,content,fullName 和 bio。

每当一个 struct 字段嵌入另一个 struct 字段时,Go 为我们提供了访问嵌入字段的选项,就好像它们是外部结构的一部分一样。这意味着 p.author.fullName() 在第 11 行号中可以用 p.fullName() 替换。因此 details() 方法可以重写如下

  1. func (p post) details() {
  2. fmt.Println("Title: ", p.title)
  3. fmt.Println("Content: ", p.content)
  4. fmt.Println("Author: ", p.fullName())
  5. fmt.Println("Bio: ", p.bio)
  6. }

现在我们已经准备好了 authorpost 结构,让我们通过创建一个博客文章来完成这个程序。

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. type author struct {
  6. firstName string
  7. lastName string
  8. bio string
  9. }
  10. func (a author) fullName() string {
  11. return fmt.Sprintf("%s %s", a.firstName, a.lastName)
  12. }
  13. type post struct {
  14. title string
  15. content string
  16. author
  17. }
  18. func (p post) details() {
  19. fmt.Println("Title: ", p.title)
  20. fmt.Println("Content: ", p.content)
  21. fmt.Println("Author: ", p.fullName())
  22. fmt.Println("Bio: ", p.bio)
  23. }
  24. func main() {
  25. author1 := author{
  26. "Naveen",
  27. "Ramanathan",
  28. "Golang Enthusiast",
  29. }
  30. post1 := post{
  31. "Inheritance in Go",
  32. "Go supports composition instead of inheritance",
  33. author1,
  34. }
  35. post1.details()
  36. }

Run in playground

上面程序中的主要功能是在第 31 中创建一个新作者。 在第 36 行创建一个新文章,嵌入了 author1。这个程序输出,

  1. Title: Inheritance in Go
  2. Content: Go supports composition instead of inheritance
  3. Author: Naveen Ramanathan
  4. Bio: Golang Enthusiast


嵌入结构切片


我们可以将这个例子更进一步拓展,用一小段博客文章创建一个网站:)。

让我们首先定义网站结构。请在现有程序的主要功能之上添加以下代码并运行它。

  1. type website struct {
  2. []post
  3. }
  4. func (w website) contents() {
  5. fmt.Println("Contents of Website\n")
  6. for _, v := range w.posts {
  7. v.details()
  8. fmt.Println()
  9. }
  10. }

在添加上述代码后运行上述程序时,编译器会报错如下

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

这个错误指向 structs []post 的嵌入切片。原因是不能匿名嵌入一个切片,而需要一个字段名。让我们修改这个错误,让编译器正常。

  1. type website struct {
  2. posts []post
  3. }

我已经将字段名 posts 添加到 post []post 的切片中。

现在让我们修改主函数,并为我们的新网站创建一些文章。

修改 main 函数后的完整程序如下

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. type author struct {
  6. firstName string
  7. lastName string
  8. bio string
  9. }
  10. func (a author) fullName() string {
  11. return fmt.Sprintf("%s %s", a.firstName, a.lastName)
  12. }
  13. type post struct {
  14. title string
  15. content string
  16. author
  17. }
  18. func (p post) details() {
  19. fmt.Println("Title: ", p.title)
  20. fmt.Println("Content: ", p.content)
  21. fmt.Println("Author: ", p.fullName())
  22. fmt.Println("Bio: ", p.bio)
  23. }
  24. type website struct {
  25. posts []post
  26. }
  27. func (w website) contents() {
  28. fmt.Println("Contents of Website\n")
  29. for _, v := range w.posts {
  30. v.details()
  31. fmt.Println()
  32. }
  33. }
  34. func main() {
  35. author1 := author{
  36. "Naveen",
  37. "Ramanathan",
  38. "Golang Enthusiast",
  39. }
  40. post1 := post{
  41. "Inheritance in Go",
  42. "Go supports composition instead of inheritance",
  43. author1,
  44. }
  45. post2 := post{
  46. "Struct instead of Classes in Go",
  47. "Go does not support classes but methods can be added to structs",
  48. author1,
  49. }
  50. post3 := post{
  51. "Concurrency",
  52. "Go is a concurrent language and not a parallel one",
  53. author1,
  54. }
  55. w := website{
  56. posts: []post{post1, post2, post3},
  57. }
  58. w.contents()
  59. }

Run in playground

在上面的主函数中,我们创建了一个author author1 和三个 posts post1, post2post3。最后我们在 63 行创建了网站 w 。通过嵌入这 3 篇文章并在下一行显示内容。

这个程序将输出

  1. Contents of Website
  2. Title: Inheritance in Go
  3. Content: Go supports composition instead of inheritance
  4. Author: Naveen Ramanathan
  5. Bio: Golang Enthusiast
  6. Title: Struct instead of Classes in Go
  7. Content: Go does not support classes but methods can be added to structs
  8. Author: Naveen Ramanathan
  9. Bio: Golang Enthusiast
  10. Title: Concurrency
  11. Content: Go is a concurrent language and not a parallel one
  12. Author: Naveen Ramanathan
  13. Bio: Golang Enthusiast


原文链接

https://golangbot.com/inheritance/