go不是面向对象语言,没有类的概念,它通过struct(structure简称)为开发者提供了自定义类型的方法。像面向对象中的类一样,struct可以用来管理一组属性集合,只是没有继承功能。

声明一个struct

type Person struct {
    name string
    email string
    age  int
}

通过type关键字定义了一个名为Person的struct, 该struct包含name,email和age属性以及它们的类型。

如果属性中类型相同也可以写在同一行。

type Person struct {
    name, email string
    age  int
}

struct的getter和setter方法:

  # 带有属性名(字段名顺序无关)
  p := Person {
      name: "Timy",
      email: "timy@gmail.com",
      age: 20,
  }

  # 也可以这样写:
  var p Person
  p.name = "Timy"
  p.email = "timy@gmail.com"
  p.age = 20
  
  # 或者更简单的:
  p := Person{"Timy","timy@gmail.com", 20}

  # 访问struct的属性
  fmt.Println(p.name) //返回Timy

注: 上面带有属性名赋值的代码中,最后一行必须有逗号,这样go在编译时就不会自动在最后一行加上分号而导致错误。

你也可以只声明一部分属性,其它属性留空(会默认为对应类型的空值)

p := Person {
  name: "Romy",
}
fmt.Println(p)

# 会打印出{Romy  0}即: Romy, "", 0. 后两个分别为string和int的默认值。

有一点注意的是p := Person{"Timy"}这种写法是不可以的,它会严格验证字段数量。

嵌套类型struct:

type Roles struct {
    roleName string
}

type Person struct {
  name, email string
  age int
  roles Roles
}
roles := Roles{"admin"}
p := Person{
    name: "Jimy",
    email: "Jimy@gmail.com",
    age: 30,
    roles: roles,
}

fmt.Println(p.roles.roleName) #=> admin

匿名struct

不用提前声明struct名称,直接创建struct,在创建一个不需要复用的struct时比较有用。

jimy := struct {
    name, email string
    age int
} {
  name: "Jimy",
  email: "Jimy@gmail.com",
  age: 30,
}
fmt.Println(jimy.name)

struct的指针

除了直接创建struct,我们还可以创建指向一个struct的指针。

p := &Person{
    name: "Jimy",
    email: "Jimy@gmail.com",
    age: 30,
 }
 fmt.Println(p.name) //这时候p是一个指针

匿名字段

在声明struct时,你可以不指定字段名,只指定类型,这样go会自动将类型映射为字段名。

type User struct {
  string
  int
}

u := User{"Mr blue", 100}
fmt.Println(u.string)  #=> Mr blue

我们上面已经看到在只声明值类型时,go会自动的将其映射成字段名,在嵌套struct中也有类似的机制.

type Roles struct {
    roleName string
}

type Person struct {
  name, email string
  age int
  Roles
}

p := Person{
    name: "Jimy",
    email: "Jimy@gmail.com",
    age: 30,
    Roles: Roles{"admin"},
}
  
fmt.Println(p.Roles.roleName)  #=> admin

struct比较

两个struct可以进行比较,如果它们属于同一个类型,且有相同的值

p := Person {
  name: "Romy", age: 0,
}
p1 := Person {
  name: "Romy", age: 0,
}
fmt.Println(p == p1)

p := Person {
    name: "Romy", age: 30,
}
p1 := Person {
    age: 30, name: "Romy",
}

fmt.Println(p == p1)

上面两种写法都会打印出true, 也表明struct比较是字段顺序无关的。

Struct field meta-data

struct也提供了向字段添加meta-data的能力。通常是用来给字段标注一下转换信息。但是你可以使用它存储任何meta-info最为标签或者说明

type Person struct {
    name string `json:"name"`
    email string  `json:"email"`
    age  int `json:"age"`
}

上述代码中,我们声明了Person struct的字段为json类型,需要通过JSON encoding/decoding来操作。

参考: https://medium.com/rungo/structures-in-go-76377cc106a2

https://golangbyexample.com/struct-field-meta-or-tags/