第 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 // 未导出,只能在当前包访问
练习题
- 定义
Book结构体,包含书名、作者和价格字段。 - 为
Rectangle添加Area和Perimeter方法。 - 使用指针接收者实现银行账户的存款和取款。
- 为
Student添加平均分和及格判断方法。 - 定义
Product和Cart,实现购物车添加、删除和计算总价。 - 使用结构体组合定义员工和地址。
- 使用 JSON 标签实现通讯录与 JSON 字符串的转换。
示例代码位于 E:\Project\Golang-Start\chapter-04-structs\examples。