5. 结构体与方法
这是什么:结构体(struct) = 把一组相关数据捆在一起的类型;方法 = 带着接收者的函数,让这捆数据「会做事」。
为什么用:上一章的变量都是各自独立的散装数据,想表示「一个用户」就得写四个变量传来传去。Go 没有 class,用 struct + 方法组合照样能造出带数据和行为的对象。
如何用:先定义一个 User 结构体并初始化它,再给字段挂上方法,最后用嵌入结构体验「组合代替继承」。
5.1 定义与使用 struct
type User struct {
Name string // 首字母大写 = 公开字段
Age int
tags []string
}
func main() {
u := User{Name: "青蛙", Age: 11} // 字段名初始化(推荐)
u.Age++ // 点号访问
fmt.Println(u.Age) // 12
p := &User{Name: "熊猫"} // 指针变量,但点号照用
p.Age = 9 // Go 自动帮你解引用
}
5.2 方法:自带接收者的函数
type User struct {
Name string
Age int
}
// 值接收者:得到副本(不改原数据)
func (u User) IsAdult() bool {
return u.Age >= 18
}
// 指针接收者:操作原数据(能改!)
func (u *User) Birthday() {
u.Age++
}
u := User{Name: "青蛙", Age: 11}
u.Birthday()
fmt.Println(u.IsAdult(), u.Age) // false 12
选择口诀:要改原数据/结构体大 →
*T指针接收者;只读小数据 →T。日常多半*T。
5.3 组合代替继承(Go 无 class 的理由)
type Animal struct{ Name string }
func (a Animal) Eat() { fmt.Println(a.Name, "在吃") }
type Dog struct {
Animal // 嵌入(组合)
Breed string
}
d := Dog{Animal: Animal{Name: "旺财"}, Breed: "柴犬"}
d.Eat() // 直接调用嵌入结构的方法 → 旺财 在吃
「有得吃就吃」(组合优于继承)正是 Go 的设计取向,比 Java 多重抽象轻多了。
5.4 结构体标签(JSON 场景速递)
type Article struct {
Title string `json:"title"`
Views int `json:"views"`
IsHot bool `json:"is_hot,omitempty"` // 空值不输出
}
配合标准库 encoding/json 与后端教程(Web 返回 JSON)直接可用。
5.5 动手改
- 给 User 加方法
Describe()返回「青蛙今年 12 岁」格式字符串 - 用指针接收者写
Rename(newName),验证原值变 - 给 Dog 嵌入 User —— 体感组合的自由
5.6 小结
- struct 定义型,
字段名:初始化、点号访问 - 方法 = 接收者 + 函数;改原数据用指针接收者
- 嵌入= 组合,替代继承链的负担
下一章:接口与错误处理 🐸