使用结构体

  1. package main
  2. import "fmt"
  3. type Books struct {
  4. title string
  5. author string
  6. subject string
  7. book_id int
  8. }
  9. func main() {
  10. // 创建一个新的结构体
  11. fmt.Println(Books{"Go 语言", "www.runoob.com", "Go 语言教程", 6495407})
  12. // 也可以使用 key => value 格式
  13. fmt.Println(Books{title: "Go 语言", author: "www.runoob.com", subject: "Go 语言教程", book_id: 6495407})
  14. // 忽略的字段为 0 或 空
  15. fmt.Println(Books{title: "Go 语言", author: "www.runoob.com"})
  16. }
  17. {Go 语言 www.runoob.com Go 语言教程 6495407}
  18. {Go 语言 www.runoob.com Go 语言教程 6495407}
  19. {Go 语言 www.runoob.com 0}

结构体不可以定义一个相同结构体类型的成员变量,也就是聚合类型不能包含自己,数组也是有同样的限制。但是结构体中可以定义一个相同结构体类型的指针用来实现例如:链表,树等数据结构

  1. type tree struct {
  2. value int
  3. left, right *tree
  4. }

结构体嵌套和匿名成员

Go允许我们定义不带名称的结构体成员,只需要指定类型即可;这种结构体成员成为匿名成员。这种结构体成员的类型必须是一个命名类型或者指向命名类型的指针。

  1. type Circle struct {
  2. Point
  3. Radius int
  4. }
  5. type Wheel struct {
  6. Circle
  7. Spokes int
  8. }
  9. type Point struct {
  10. X Y int
  11. }

提供结构体嵌套功能之后,可以直接访问我们需要的变量

  1. var w wheel
  2. w.X = 8 // 等价于w.Circle.Point.X=8
  3. w.Y = 8

结构体的可见性

  1. 结构体命名小写的话对于别的包是不可见的,这中情况下在序列化和反序列化时会存在字段丢失的问题
  2. 结构体中各个字段小写开头的话对于其他包也是不可见,并且无法赋值的,同一个包中没有此限制

type定义类型别名

  1. type name underlying-name
  2. type Celsius float64 // 别名的大小写同样决定了包的可见性
  3. type Fahrenheit float64
  4. func CToF(c Celsius) Fahrenheit { return Fahrenheit(c*9/5 + 32)}
  5. func FToC(f Fahrenheit) Celsius { return Celsius((f - 32) * 5 / 9)}

在以上定义了两个类型Celsius(摄氏温度),Fahrenheit(华氏温度),它们分别对应两种温度计量单位,即使底层类型都是float64,它们也不是相同的类型,所以它们不能使用算术表达式进行比较和合并。区分这些类型可以防止无意间将这两种计量单位的值直接合并
从float64转化成Celsius(t) 或者Fahrenheit(t) 需要显示的类型转化,对于每一个类型T,都有一个类型转化操作T(x),将值x转化成类型T,这个是类型转化操作,而不是函数调用。如果两个类型具有相同的底层类型或者二者都是指向相同底层类型变量的未命名指针类型,那么两者是可以互相转化的。命名类型的底层类型决定了它的结构和表达式,以及它支持的内部操作集合

类型的String方法

  1. func (c Celsius) String() string { return fmt.Sprintf("%g℃", c)}

在func和方法名String()之间添加的 (c Celsius) 是方法的接收者,这样定义的方法的作用类似于java中的toString的方法。