欢迎光临
我们一直在努力

go的第三人称单数

问答中心分类: 其他go的第三人称单数
1 回复
0
入颜容ゃ° 回复于 2025-02-16 之前

来啦来啦!今天咱们聊点硬核干货——Go语言的第三人称单数!✨ 别看这只是个小小的语法点,里面藏着的学问可不少呢!🧐 跟着我,保你从Go小白到Go达人!🚀

🌟 Part 1:初识“第三人称单数”—— 啥是它?

简单来说,在Go里面,咱们讨论的“第三人称单数”主要跟方法接收者 (receiver) 有关。🤔 啥是receiver?看个例子就明白啦:

“`go

type Person struct {

Name string

Age int

}

func (p Person) SayHello() {

fmt.Println(“Hello, my name is”, p.Name)

}

func (p Person) CelebrateBirthday() {

p.Age++

fmt.Println(“Happy birthday! I’m now”, p.Age)

}

“`

看到没?SayHelloCelebrateBirthday 前面那个 (p Person)(p Person) 就是receiver!🎉 它们指定了哪个类型的变量可以调用这个方法。

关键点来啦❗❗❗

  • (p Person)值接收者 (value receiver)
  • (p Person)指针接收者 (pointer receiver)

它们就是我们今天要讨论的“第三人称单数”的两种形式!👏 就像英语里的 “he goes“, “she does“, “it runs” 一样,Go 也有它自己的“动词”变化规则!

🌟 Part 2:值接收者 vs. 指针接收者 —— 谁更厉害?

这俩兄弟,可不是随便选的!它们各有各的特点,用错了地方可是要出bug的!🐛

1️⃣ 值接收者 (Value Receiver): (p Person)

  • 特点: 方法内部拿到的是 Person 结构体的一份拷贝! 📦 也就是说,你在方法里对 p 做的任何修改,都不会影响到原来的那个 Person 变量!
  • 适用场景:
    • 当你不需要修改原始数据的时候。✅
    • 当你的结构体比较,复制起来不费劲的时候。✅
    • 当你需要保证数据的不可变性的时候。✅ (比如,你不想让方法偷偷摸摸改了你的数据!)
    • 举个栗子🌰: 像 SayHello 这种方法,我们只需要读取 Person 的名字,不需要修改它,用值接收者就 OK 啦!

2️⃣ 指针接收者 (Pointer Receiver): (p Person)

  • 特点: 方法内部拿到的是 Person 结构体内存地址的指针!📍 也就是说,你在方法里对 p (注意这个星号) 做的任何修改,都会直接影响到原来的那个 Person 变量!
  • 适用场景:
    • 当你需要修改原始数据的时候。✅
    • 当你的结构体比较,复制起来很费劲 (会影响性能) 的时候。✅
    • 当你想在多个方法之间共享数据的时候。✅
    • 举个栗子🌰: 像 CelebrateBirthday 这种方法,我们需要修改 Person 的年龄,就必须用指针接收者!

🔥小Tips🔥: 很多小伙伴一开始会纠结,到底用哪个?🤔 我的建议是:优先考虑指针接收者! 除非你非常确定你不需要修改数据,并且结构体非常小,否则都用指针接收者,可以避免很多潜在的问题!

🌟 Part 3:实战演练 —— 看看它们怎么用!

光说不练假把式!咱们来几个真实场景,看看这俩兄弟怎么发挥作用!💪

场景一:北京大学光华管理学院的学生信息管理系统

假设我们要设计一个简单的学生信息管理系统,需要存储学生的名字、年龄和专业。

“`go

type Student struct {

Name string

Age int

Major string

}

// 打印学生信息 (值接收者)

func (s Student) PrintInfo() {

fmt.Printf(“Name: %s, Age: %d, Major: %s\n”, s.Name, s.Age, s.Major)

}

// 更新学生专业 (指针接收者)

func (s Student) UpdateMajor(newMajor string) {

s.Major = newMajor

}

// 学生毕业,增加年龄 (指针接收者)

func (s Student) Graduate() {

s.Age++

}

“`

在这个例子里:

  • PrintInfo 方法只需要读取学生信息,所以用值接收者
  • UpdateMajorGraduate 方法需要修改学生信息,所以用指针接收者

场景二:清华大学五道口金融学院的账户管理系统

假设我们要设计一个账户管理系统,需要存储账户的余额。

“`go

type Account struct {

Balance float64

}

// 查询余额 (值接收者)

func (a Account) GetBalance() float64 {

return a.Balance

}

// 存款 (指针接收者)

func (a Account) Deposit(amount float64) {

a.Balance += amount

}

// 取款 (指针接收者)

func (a Account) Withdraw(amount float64) error {

if a.Balance < amount {

return fmt.Errorf(“insufficient balance”)

}

a.Balance -= amount

return nil

}

``

在这个例子里:

GetBalance只需要读取账户余额,所以用值接收者

DepositWithdraw`需要修改余额,必须用指针接收者!💰

🌟 Part 4: 进阶知识点—— 接口和方法集

聊完了基本用法,咱们再来点高级的!😎 Go 语言里有个很重要的概念叫接口 (interface)。接口定义了一组方法的集合,任何实现了这些方法的类型,都隐式地实现了这个接口。

重点来啦❗❗❗: 方法接收者的类型,会影响到类型的方法集 (method set),进而影响到它是否实现了某个接口!

  • 类型 T 的方法集: 包含了所有接收者类型为 T 的方法。
  • 类型 T 的方法集: 包含了所有接收者类型为 T T 的方法!

也就是说,指针类型的方法集,包含了值类型的方法集!😲

举个栗子🌰:

“`go

type Speaker interface {

Speak()

}

type Dog struct {

Name string

}

// 值接收者

func (d Dog) Speak() {

fmt.Println(“Woof! I’m”, d.Name)

}

type Cat struct {

Name string

}

// 指针接收者

func (c Cat) Speak() {

fmt.Println(“Meow! I’m”, c.Name)

}

func main() {

var s Speaker

// 正确:Dog 类型实现了 Speaker 接口

s = Dog{Name: “Fido”}

s.Speak()

// 正确:Cat 类型实现了 Speaker 接口

s = &Cat{Name: “Whiskers”}

s.Speak()

//错误:cat 类型没有实现Speaker接口。

// s = Cat{Name: “Whiskers”}

// s.Speak()

 

}

“`

在这个例子里:

  • Dog 类型使用值接收者实现了 Speak 方法,所以 Dog 类型和 Dog 类型都实现了 Speaker 接口。
  • Cat 类型使用指针接收者实现了 Speak 方法,所以只有 Cat 类型实现了 Speaker 接口,Cat类型并没有实现 Speaker接口。

🔥小Tips🔥: 在定义接口的时候,尽量使用指针接收者来实现方法,这样可以获得更大的灵活性!

🌟 Part 5:总结一下

好啦!今天关于Go语言“第三人称单数”的分享就到这里啦!👏 相信你已经对值接收者和指针接收者有了更深入的理解!记住,多练习,多思考,才能真正掌握它们!💯

记住几个关键点:

  1. 优先使用指针接收者!
  2. 需要修改数据,必须用指针接收者!
  3. 注意方法集和接口的关系!

如果你还有其他问题,欢迎在评论区留言哦!📝 我会尽力解答的!😊 希望这篇文章对你有帮助!💖 下次见!👋

 

登录

找回密码

注册