Go 结构体
Go 语言中的结构体(struct)本质上是一种类型。我可以使用 type 关键字定义新的类型,包括结构体类型。结构体是一种复合类型,允许我将多个不同类型的数据组合在一起,形成一个单一的、更复杂的数据结构。
package main
import "fmt"
// 定义一个新的结构体类型
type Person struct {
    Name string
    Age  int
}
func main() {
    // 创建一个 Person 类型的变量
    person := Person{Name: "Alice", Age: 30}
    // 打印结构体
    fmt.Println(person)
}
结构体类型封装数据
package main
import "fmt"
// 定义一个 Car 结构体,代表汽车的概念
type Car struct {
    Make  string // 汽车品牌
    Model string // 型号
    Year  int    // 生产年份
}
// NewCar 是一个构造函数,用于创建新的 Car 实例
func NewCar(make, model string, year int) *Car {
    return &Car{
        Make:  make,
        Model: model,
        Year:  year,
    }
}
// Display 为 Car 类型定义了一个方法,用于显示汽车信息
func (c *Car) Display() {
    fmt.Printf("Car: %s %s, Year: %d\n", c.Make, c.Model, c.Year)
}
func main() {
    // 使用 NewCar 构造函数创建一个新的 Car 实例
    myCar := NewCar("Toyota", "Corolla", 2020)
    // 调用 myCar 的 Display 方法
    myCar.Display()
}
结构体初始化的方式
指定字段名称
这种方法清晰明了,也是最常用的一种。
type Person struct {
    Name string
    Age  int
}
// 初始化
person := Person{Name: "Alice", Age: 30}
这种方法创建了一个 Person 结构体的实例 person。这里 person 是一个结构体类型的变量,存储了 Person 的值。我可以直接通过 person 访问其字段。
fmt.Println(person.Name) // 直接访问
person.Age = 31          // 直接修改字段
按照字段顺序
按照结构体中字段声明的顺序来初始化,但这种方式要求我提供所有字段的值,并且一旦结构体定义改变,初始化代码也可能需要更新。
person := Person{"Bob", 25}
使用 new 关键字
使用 new 关键字可以创建一个指向结构体的指针,结构体的字段会被初始化为零值。
person := new(Person)
// person 是一个指向 Person 的指针,其字段 Name 和 Age 都是零值("" 和 0)
结构体字面量与指针
可以直接创建一个指向结构体的指针,并用字面量初始化它。
person := &Person{Name: "Eve", Age: 40}
这种方法创建了一个指向 Person 结构体的指针 person。虽然在 Go 中我仍然可以使用 person 访问其字段(Go 会自动对结构体指针进行解引用 😊),但它实际上是一个指针。
fmt.Println(person.Name) // 自动解引用
person.Age = 41          // 自动解引用,修改指针指向的结构体的字段
使用构造函数(惯用法)
虽然 Go 没有构造函数的概念,但可以定义一个函数来封装结构体的创建过程。
func NewPerson(name string, age int) *Person {
    return &Person{Name: name, Age: age}
}
person := NewPerson("Dave", 35)
策略模式
package main
import "fmt"
func main() {
    type Student struct {
        Name   string
        Age    int
        Course string
    }
    // 使用策略模式,通过 map 的 key 来区分不同的策略
    students := map[int]Student{
        1: {"John", 18, "计算机科学"},
        2: {"Peter", 20, "数学"},
        3: {"Mary", 22, "物理"},
    }
    fmt.Println(students)
    for _, student := range students {
        fmt.Println(student.Name, student.Age, student.Course)
    }
}
在这个示例中,我定义了一个 Student 结构体,用于存储学生的信息。通过使用 map,我可以根据不同的策略(这里是 key)来存储和访问学生数据。
注意事项
- 定义结构体时,字段名称应清晰明了,遵循命名规范。
- 初始化结构体时,根据需求选择合适的方式。
- 使用指针时,要注意指针的解引用,避免出现 nil指针错误。