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