Go 语言程序设计——面向对象编程(5)

结构体

  • Go 语言中创建自定义结构体最简单的方式是基于 Go 语言的内置类型创建
  • 自定义类型也可以基于结构体创建,用于聚合和嵌入
  • 与 C++ 的结构体相比,Go 语言的结构体更接近于 C 的结构体,并且由于对嵌入的完美支持,它更容易使用
points := [][2]int{{4, 6}, {}, {-7, 11}, {15, 17}, {14, -8}}
for _, point := range points {
  fmt.Printf("(%d, %d)", point[0], point[1])
}
// 通过使用匿名结构体的更好的方法
points := []struct{x, y int} {{4, 6}, {},{-7,11},{15,17},{14,-8}}
for _, point := range points {
  fmt.Printf("(%d, %d)", point.x, point.y)
}
  • 虽然结构体是匿名的,但是我们可以通过具名字段来访问其数据,这比前面所使用的数组索引更为简便和安全

结构体的聚合与嵌入

  • 我们可以像嵌入接口或者其他类型的方式来嵌入结构体
  • 通过将一个结构体的名字以匿名字段的方式放入另一个结构体来实现
  • 一个嵌入字段的字段可以通过使用 .(点)操作符来访问
  • 结构体中的每一个字段的名字都必须是唯一的
  • 对于嵌入的(匿名的)字段,唯一性要求足以保证避免歧义
嵌入值
  • 让我们看一个简单的例子,它涉及两个结构体:
type Person struct {
  Title   string        // 具名字段(聚合)
  Forenames []string      // 具名字段(聚合)
  Surname  string       // 具名字段(聚合)
}

type Author1 struct {
  Names    Person        // 具名字段(聚合)
  Title    []string      // 具名字段(聚合)
  YearBorn  int         // 具名字段(聚合)
}

type Author2 struct {
  Person                  // 具名字段(聚合)
  Title    []string      // 具名字段(聚合)
  YearBorn  int         // 具名字段(聚合)
}
  • 为了嵌入一个匿名字段,我们使用了要嵌入类型(或者接口)的名字而未声明一个变量名
  • 我们可以直接访问这些字段的字段(即无需声明类型或者接口名),或者为了与外围结构体的字段的名字区分开,使用类型或者接口的名字访问嵌入字段的字段
嵌入带方法的匿名值
  • 如果一个嵌入字段带方法,那我们就可以在外部结构体中直接调用它,并且只有嵌入的字段(而不是整个外部结构体)会作为接收者传递给这些方法
嵌入接口
  • 结构体除了可以聚合和嵌入具体的类型外,也可以聚合和嵌入接口
  • 反之在接口中聚合或者嵌入结构体是行不通的,因为接口是完全抽象的概念,所以这样的聚合与嵌入毫无意义
  • 当一个结构体包含聚合(具名的)或者嵌入(匿名的)接口类型的字段时,这意味着该结构体可以将任意满足该接口规格的值存储在该字段中

推荐阅读更多精彩内容