Skip to main content

第 4 章:结构体与方法

本章目标​

  • 使用 struct 将多个相关字段组合成自己的类型
  • 创建结构体实例并访问、修改字段
  • 为结构体定义方法
  • 区分值接收者和指针接收者
  • 使用结构体组合复用字段和方法
  • 使用 JSON 标签控制结构体与 JSON 的转换

结构体基础​

使用 type 和 struct 定义自己的数据类型:

type User struct {
Name string
Age int
}

创建实例的推荐方式是使用字段名:

user := User{
Name: "小明",
Age: 20,
}

fmt.Println(user.Name)
user.Age++

结构体的零值是所有字段各自类型的零值:

var user User
fmt.Println(user.Name) // 空字符串
fmt.Println(user.Age) // 0

结构体指针可以直接使用点号访问字段,Go 会自动解引用:

userPointer := &user
userPointer.Age = 21

方法​

方法是绑定到某个类型上的函数:

type Rectangle struct {
Width float64
Height float64
}

func (r Rectangle) Area() float64 {
return r.Width * r.Height
}

调用方法:

rectangle := Rectangle{Width: 5, Height: 3}
fmt.Println(rectangle.Area())

r Rectangle 是接收者,表示这个方法属于 Rectangle。

值接收者和指针接收者​

值接收者会得到结构体的一份副本,适合只读取数据的方法:

func (r Rectangle) Area() float64 {
return r.Width * r.Height
}

指针接收者可以修改原结构体:

type Account struct {
Balance float64
}

func (a *Account) Deposit(amount float64) {
a.Balance += amount
}

调用时通常不需要手动写 &:

account := Account{}
account.Deposit(100)

编译器会在可寻址的变量上自动取得地址。

结构体组合​

Go 没有传统面向对象语言中的类继承,通常通过组合复用数据和行为:

type Address struct {
City string
}

type Employee struct {
Name string
Address
}

employee := Employee{
Name: "小红",
Address: Address{City: "杭州"},
}

fmt.Println(employee.City)

嵌入的 Address 字段和方法可以被提升访问。

JSON 标签​

encoding/json 可以在结构体和 JSON 之间转换:

type Contact struct {
Name string `json:"name"`
Phone string `json:"phone"`
Email string `json:"email,omitempty"`
}
data, err := json.Marshal(contact)
if err != nil {
return
}

var decoded Contact
err = json.Unmarshal(data, &decoded)

结构体字段首字母必须大写,encoding/json 默认只处理导出字段。omitempty 表示字段为零值时可以省略。

导出规则​

Go 通过首字母大小写控制跨包可见性:

Name string // 导出,可被其他包访问
name string // 未导出,只能在当前包访问

练习题​

  1. 定义 Book 结构体,包含书名、作者和价格字段。
  2. 为 Rectangle 添加 Area 和 Perimeter 方法。
  3. 使用指针接收者实现银行账户的存款和取款。
  4. 为 Student 添加平均分和及格判断方法。
  5. 定义 Product 和 Cart,实现购物车添加、删除和计算总价。
  6. 使用结构体组合定义员工和地址。
  7. 使用 JSON 标签实现通讯录与 JSON 字符串的转换。

示例代码位于 E:\Project\Golang-Start\chapter-04-structs\examples。