跳到主要内容

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 指针错误。