Appearance
第 11 章:结构体与方法
11.1 结构体定义与初始化
结构体是一种复合数据类型,它可以包含多个不同类型的字段。
结构体定义
go
type Person struct {
Name string
Age int
City string
}结构体初始化
方式 1:指定字段名
go
p1 := Person{
Name: "Alice",
Age: 25,
City: "Beijing",
}方式 2:按顺序初始化
go
p2 := Person{"Bob", 30, "Shanghai"}方式 3:使用 new
go
p3 := new(Person)
p3.Name = "Charlie"
p3.Age = 35
p3.City = "Guangzhou"访问结构体字段
go
fmt.Println(p1.Name, p1.Age, p1.City)11.2 结构体嵌套
结构体可以嵌套其他结构体,实现组合复用:
基本嵌套
go
type Address struct {
Street string
City string
ZipCode string
}
type Person struct {
Name string
Age int
Address Address // 嵌套结构体
}
// 初始化
p := Person{
Name: "Alice",
Age: 25,
Address: Address{
Street: "Main St",
City: "Beijing",
ZipCode: "100000",
},
}
// 访问嵌套字段
fmt.Println(p.Address.City)匿名嵌套
go
type Person struct {
Name string
Age int
Address // 匿名嵌套
}
// 初始化
p := Person{
Name: "Alice",
Age: 25,
Address: Address{
Street: "Main St",
City: "Beijing",
ZipCode: "100000",
},
}
// 直接访问嵌套字段(提升字段)
fmt.Println(p.City) // 等同于 p.Address.City11.3 方法:给结构体绑定函数
方法是与结构体关联的函数,它可以访问和修改结构体的字段。
方法定义
go
func (p Person) greet() {
fmt.Printf("Hello, my name is %s.\n", p.Name)
}
// 调用方法
p := Person{Name: "Alice"}
p.greet()方法与函数的区别
- 方法有接收者,函数没有
- 方法可以访问接收者的字段
- 方法是结构体的行为,函数是独立的
11.4 值接收者与指针接收者
值接收者
值接收者会复制接收者的值,修改不会影响原结构体:
go
func (p Person) setAge(age int) {
p.Age = age // 修改的是副本
}
p := Person{Name: "Alice", Age: 25}
p.setAge(30)
fmt.Println(p.Age) // 输出 25,原结构体未被修改指针接收者
指针接收者接收结构体的指针,修改会影响原结构体:
go
func (p *Person) setAge(age int) {
p.Age = age // 修改的是原结构体
}
p := Person{Name: "Alice", Age: 25}
(&p).setAge(30)
// 或简化为
p.setAge(30) // Go 会自动取地址
fmt.Println(p.Age) // 输出 30,原结构体被修改选择建议
- 当需要修改接收者时,使用指针接收者
- 当接收者是大型结构体时,使用指针接收者(避免复制开销)
- 当接收者是基本类型或小结构体时,使用值接收者
11.5 结构体实战案例
案例 1:矩形结构体
go
package main
import "fmt"
type Rectangle struct {
Width float64
Height float64
}
// 计算面积
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
// 计算周长
func (r Rectangle) Perimeter() float64 {
return 2 * (r.Width + r.Height)
}
// 修改尺寸
func (r *Rectangle) Resize(width, height float64) {
r.Width = width
r.Height = height
}
func main() {
rect := Rectangle{Width: 10, Height: 5}
fmt.Printf("Area: %.2f\n", rect.Area())
fmt.Printf("Perimeter: %.2f\n", rect.Perimeter())
rect.Resize(15, 8)
fmt.Printf("After resize - Area: %.2f\n", rect.Area())
fmt.Printf("After resize - Perimeter: %.2f\n", rect.Perimeter())
}案例 2:学生管理
go
package main
import "fmt"
type Student struct {
ID int
Name string
Score float64
}
func (s Student) GetGrade() string {
switch {
case s.Score >= 90:
return "A"
case s.Score >= 80:
return "B"
case s.Score >= 60:
return "C"
default:
return "D"
}
}
func main() {
students := []Student{
{ID: 1, Name: "Alice", Score: 95},
{ID: 2, Name: "Bob", Score: 82},
{ID: 3, Name: "Charlie", Score: 75},
{ID: 4, Name: "David", Score: 58},
}
for _, s := range students {
fmt.Printf("%s: Score=%.1f, Grade=%s\n", s.Name, s.Score, s.GetGrade())
}
}