Skip to content

第 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.City

11.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())
    }
}

© 2026 编程马·菜鸟教程 版权所有