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 接口,自定义打印格式
接收者一致性 一个类型应统一使用值接收者或指针接收者
相关推荐
Go_error3 小时前
Fyne:让 Go 开发者也能玩转 GUI
后端·go
Go_error3 小时前
Go 实现 Mysql AES 与 Scanner/Valuer 自动加解密
go
Go_error3 小时前
Badu/bus:Go 轻量级泛型发布/订阅事件总线
后端·go
Go_error3 小时前
Go-redis:执行 Lua 脚本
后端·go
stark张宇7 小时前
Go并发调度器源码探秘:GMP模型之G/M/P底层数据结构完全拆解
go
学习星球1 天前
# 6G通感一体化(ISAC)技术深度解析——从原理到实战> <br />
go·信息与通信·媒体
小满zs1 天前
Go语言第十章(指针)
后端·google·go
学习星球2 天前
6G核心网架构深度解析——AI Native时代的网络变革
网络·人工智能·5g·架构·go·信息与通信
ylj_dev3 天前
从 0 构建 AI Workload Platform(九):真实场景、最小控制台与开源发布
go·react·开源项目·工作流·ai agent