8.2 Go Struct 方法学习笔记

8.2 Go Struct 方法学习笔记

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

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

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)
}

调用方式:

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() 方法,但它们是不同类型的接收者,不会冲突:

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

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

调用时,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. 指针接收者 — 修改原值

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

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
}

调用后原值被修改:

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(不变)

执行结果:

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)
// 值接收者 — 只读取,不修改
func (ba BankAccount) GetBalance() float64 {
    return ba.Balance
}

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

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


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

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

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

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

{AccountNumber:12345 Balance:1000}

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

Account 12345: $1000.00

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

type Stringer interface {
    String() string
}

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


知识点总结

知识点 关键概念
方法定义 func (接收者 类型) 方法名(参数) 返回值,接收者写在函数名前
值接收者 操作拷贝,不修改原值,适合只读方法
指针接收者 操作原值,可以修改,适合需要变更的方法
同名方法 不同类型可以有同名方法,Go 根据调用对象类型自动选择
String() 方法 实现 fmt.Stringer 接口,自定义打印格式
接收者一致性 一个类型应统一使用值接收者或指针接收者
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容