Go 结构体和方法
本章将深入介绍 Go 语言中的结构体和方法。
结构体定义
基本结构体
type Person struct {
Name string
Age int
City string
}
// 创建实例
p := Person{Name: "张三", Age: 25, City: "北京"}
命名规则
结构体名通常使用驼峰式,首字母大写表示导出:
type Student struct {
Name string // 导出字段
score float64 // 未导出字段
}
结构体内存布局
结构体占用连续内存空间:
type Point struct {
X int
Y int
}
p := Point{X: 10, Y: 20}
fmt.Printf("地址: %p\n", &p)
fmt.Printf("X 地址: %p, Y 地址: %p\n", &p.X, &p.Y)
方法
方法定义
Go 中的方法是与特定类型绑定的函数:
type Rectangle struct {
Width float64
Height float64
}
// 值接收者方法
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
// 指针接收者方法
func (r *Rectangle) Scale(factor float64) {
r.Width *= factor
r.Height *= factor
}
rect := Rectangle{Width: 10, Height: 5}
fmt.Println(rect.Area()) // 50
rect.Scale(2)
fmt.Println(rect.Area()) // 200
值接收者 vs 指针接收者
| 场景 | 推荐使用 |
|---|---|
| 方法不需要修改结构体 | 值接收者 |
| 方法需要修改结构体 | 指针接收者 |
| 结构体较大 | 指针接收者 |
| 结构体包含 sync.RWMutex | 指针接收者 |
何时使用指针
type Counter struct {
count int
}
// ❌ 值接收者:无法修改
func (c Counter) Increment() {
c.count++
}
// ✅ 指针接收者:可以修改
func (c *Counter) Increment() {
c.count++
}
// 何时使用值接收者
func (c Counter) GetCount() int {
return c.count // 只读取不修改
}
结构体嵌套
匿名嵌套
type Address struct {
City string
State string
}
type Person struct {
Name string
Address // 匿名嵌套
}
p := Person{
Name: "张三",
Address: Address{
City: "北京",
State: "北京",
},
}
// 可以直接访问嵌套字段
fmt.Println(p.City) // 北京
fmt.Println(p.Address.City) // 北京
命名嵌套
type Address struct {
City string
State string
}
type Person struct {
Name string
Home Address // 命名嵌套
Work Address
}
p := Person{
Name: "张三",
Home: Address{City: "北京", State: "北京"},
Work: Address{City: "上海", State: "上海"},
}
多层嵌套
type Country struct {
Name string
}
type Province struct {
Country Country
Name string
}
type City struct {
Province Province
Name string
}
c := City{
Province: Province{
Country: Country{Name: "中国"},
Name: "四川",
},
Name: "成都",
}
fmt.Println(c.Province.Country.Name) // 中国
结构体相等性
可比较的结构体
如果结构体的所有字段都是可比较的,结构体也可以比较:
type Point struct {
X int
Y int
}
p1 := Point{X: 1, Y: 2}
p2 := Point{X: 1, Y: 2}
p3 := Point{X: 2, Y: 1}
fmt.Println(p1 == p2) // true
fmt.Println(p1 == p3) // false
不可比较的结构体
包含切片、映射、函数的结构体不能比较:
type Person struct {
Name string
hobbies []string // 切片,不可比较
}
// ❌ 编译错误
// fmt.Println(p1 == p2)
JSON 序列化
基本序列化
import "encoding/json"
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
City string `json:"city,omitempty"` // 空值省略
}
p := Person{Name: "张三", Age: 25}
// 序列化为 JSON
data, err := json.Marshal(p)
fmt.Println(string(data))
// {"name":"张三","age":25,"city":""}
// 格式化输出
data, _ = json.MarshalIndent(p, "", " ")
fmt.Println(string(data))
反序列化
jsonStr := `{"name":"李四","age":30,"city":"上海"}`
var p Person
err := json.Unmarshal([]byte(jsonStr), &p)
fmt.Println(p.Name, p.Age, p.City) // 李四 30 上海
忽略字段
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
password string `json:"-"` // 忽略此字段
}
构造函数
Go 没有内置构造函数,但可以创建工厂函数:
type Person struct {
Name string
Age int
}
// 构造函数
func NewPerson(name string, age int) *Person {
return &Person{
Name: name,
Age: age,
}
}
// 使用
p := NewPerson("张三", 25)
多构造函数
type Person struct {
Name string
Age int
Email string
}
// 普通构造函数
func NewPerson(name string, age int) *Person {
return &Person{Name: name, Age: age}
}
// 带邮箱的构造函数
func NewPersonWithEmail(name string, age int, email string) *Person {
return &Person{Name: name, Age: age, Email: email}
}
// 默认构造函数
func NewDefaultPerson() *Person {
return &Person{Name: "匿名", Age: 0}
}
组合与继承
组合模式
type Animal struct {
Name string
}
func (a *Animal) Speak() {
fmt.Println("...")
}
type Dog struct {
Animal // 嵌入
Breed string
}
func (d *Dog) Speak() {
fmt.Println("汪汪汪")
}
d := Dog{
Animal: Animal{Name: "旺财"},
Breed: "金毛",
}
d.Speak() // 汪汪汪(自己定义的)
d.Animal.Speak() // ...(嵌入的)
接口组合
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
// 组合接口
type ReadWriter interface {
Reader
Writer
}
小结
- 结构体:自定义复合类型
- 方法:与类型绑定的函数
- 指针接收者:用于修改结构体或大结构体
- 嵌套:匿名嵌套和命名嵌套
- JSON:结构体标签控制序列化
- 构造函数:工厂函数模式
练习
- 定义一个矩形结构体,实现面积和周长计算方法
- 创建一个学生结构体,包含姓名、年龄和多门课程成绩
- 给学生结构体添加计算平均成绩的方法
- 实现一个 Person 结构体的 JSON 序列化
- 使用嵌套结构体创建公司组织结构