8.2 Go Struct 方法学习笔记

8.2 Go Struct 方法学习笔记

1. 方法的定义 --- 值接收者

方法就是带"接收者"的函数。接收者写在函数名前面,用 (r Type) 的格式:

go 复制代码
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)
}

调用方式:

go 复制代码
rect := Rectangle{Width: 5, Height: 3}
fmt.Printf("Area: %.2f\n", rect.Area())        // 15.00
fmt.Printf("Perimeter: %.2f\n", rect.Perimeter()) // 16.00

值接收者 func (r Rectangle):方法操作的是结构体的拷贝,不会修改原值。适合只读取数据、不修改数据的方法。


2. 不同类型可以有同名方法

Rectangle 和 Circle 都有 Area() 方法,但它们是不同类型的接收者,不会冲突:

go 复制代码
func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

func (c Circle) Area() float64 {
    return math.Pi * c.Radius * c.Radius
}

调用时,Go 根据调用对象的类型自动选择对应的方法:

go 复制代码
rect := Rectangle{Width: 5, Height: 3}
circle := Circle{Radius: 4}

rect.Area()    // 调用 Rectangle 的 Area → 15.00
circle.Area()  // 调用 Circle 的 Area → 50.27

Go 没有类继承,但不同类型可以有同名方法,这是实现接口的基础。


3. 指针接收者 --- 修改原值

当方法需要修改结构体本身时,必须使用指针接收者

go 复制代码
type BankAccount struct {
    AccountNumber string
    Balance       float64
}

func (ba *BankAccount) Deposit(amount float64) {
    ba.Balance += amount  // 直接修改原值
}

func (ba *BankAccount) Withdraw(amount float64) bool {
    if ba.Balance >= amount {
        ba.Balance -= amount  // 直接修改原值
        return true
    }
    return false
}

调用后原值被修改:

go 复制代码
account := BankAccount{AccountNumber: "12345", Balance: 1000.0}

account.Deposit(250)
// Balance: 1000 + 250 = 1250.00

account.Withdraw(500)   // 成功,返回 true
// Balance: 1250 - 500 = 750.00

account.Withdraw(2000)  // 失败,余额不足,返回 false
// Balance: 750.00(不变)

执行结果:

yaml 复制代码
Initial account: Account 12345: $1000.00
After deposit: Balance = 1250.00
Withdrawal successful
Cannot withdraw $2000 - insufficient funds
Final account: Account 12345: $750.00

4. 值接收者 vs 指针接收者

值接收者 func (ba BankAccount) 指针接收者 func (ba *BankAccount)
操作对象 结构体的拷贝 结构体的原值
能否修改原值 不能
适用场景 只读方法(Get、计算) 需要修改的方法(Set、Deposit、Withdraw)
go 复制代码
// 值接收者 --- 只读取,不修改
func (ba BankAccount) GetBalance() float64 {
    return ba.Balance
}

// 指针接收者 --- 需要修改原值
func (ba *BankAccount) Deposit(amount float64) {
    ba.Balance += amount
}

最佳实践:如果一个类型有任何一个方法用了指针接收者,那么所有方法都应该用指针接收者,保持一致性。


5. String() 方法 --- 实现 fmt.Stringer 接口

定义 String() 方法可以自定义结构体的打印格式:

go 复制代码
func (ba BankAccount) String() string {
    return fmt.Sprintf("Account %s: $%.2f", ba.AccountNumber, ba.Balance)
}

没有 String 方法时,fmt.Println(account) 输出:

css 复制代码
{AccountNumber:12345 Balance:1000}

有了 String 方法后,输出变为自定义格式:

bash 复制代码
Account 12345: $1000.00

这就是实现了 fmt.Stringer 接口。该接口定义如下:

go 复制代码
type Stringer interface {
    String() string
}

只要你的类型有 String() string 方法,就自动实现了这个接口,fmt.Printlnfmt.Printf 等都会调用你的 String 方法。


知识点总结

知识点 关键概念
方法定义 func (接收者 类型) 方法名(参数) 返回值,接收者写在函数名前
值接收者 操作拷贝,不修改原值,适合只读方法
指针接收者 操作原值,可以修改,适合需要变更的方法
同名方法 不同类型可以有同名方法,Go 根据调用对象类型自动选择
String() 方法 实现 fmt.Stringer 接口,自定义打印格式
接收者一致性 一个类型应统一使用值接收者或指针接收者
相关推荐
alsmile13 小时前
Node-RED 之外,国产规则引擎的新方案:基于标准语法,Go 先行实现
后端·开源·go
茉莉玫瑰花茶15 小时前
GO [ 变量 ]
go
lpfasd12316 小时前
展厅中控总体架构
go·串口·中控
茉莉玫瑰花茶20 小时前
GO [ 条件/循环控制 ]
go
茉莉玫瑰花茶20 小时前
GO [ 数据类型 ]
go
云浪2 天前
Go Context 到底是什么?
后端·go
newerp2 天前
系统调用与 M/P 解绑
后端·程序员·go
newerp2 天前
抢占式调度实现细节
后端·程序员·go
小小龙学IT2 天前
Go 语言 net/http 网络编程深度解析:从 Handler 到生产级 HTTP 服务
go
名字还没想好☜2 天前
Go 实现指数退避重试:context 取消、抖动 jitter 与什么时候别重试
后端·golang·go