Golang method receiver
class User
attr_reader :name, :age
def initialize(name:, age:)
@name = name
@age = age
end
def happy_birthday
puts 'Happy Birthday:)'
@age += 1
end
end
xiao_ming = User.new(name: '小明', age: 18)
xiao_ming.happy_birthday
puts xiao_ming.age
这是一段 Ruby 代码, 很清楚地展示了 User 里的数据(name, age)和方法(happy_birthday).
对于 Golang , 如果想要实现 xiao_ming.happy_birthday
: 向 xiao_ming
发送 happy_birthday
消息, 需要写成下面这样:
package main
import (
"fmt"
)
type User struct {
name string
age int
}
func (user User) HappyBirthday() {
fmt.Println("Happy Birthday:)")
user.age += 1
}
func (user *User) UnhappyBirthday() {
fmt.Println("Unhappy Birthday:(")
user.age += 1
}
func main() {
xiaoMing := User{"小明", 18}
xiaoMing.HappyBirthday()
fmt.Println(xiaoMing.age)
xiaoHong := User{"小红", 18}
xiaoHong.UnhappyBirthday()
fmt.Println(xiaoHong.age)
}
Golang 中, 参数是按值传递的, 接收者亦然. HappyBirthday
方法的接收者是 User
类型本身, 也就是说会复制一份然后在副本上调用方法; UnhappyBirthday
方法的接收者是 *User
引用类型, 通过指针来操作原始数据. 所以以上的outputs:
小明 18
18
小红 18
19
Golang 的编译器对引用类型比较宽容, 我们要求 UnhappyBirthday
的接收者是一个指针, 但是 xiaoHong
是一个 User
变量, 不是指针, 这种情况下也可以正常工作.
如何选择呢?
一般的想法是说: 当需要修改当前值时, 使用指针接收者; 当需要创建一个新的对象时, 使用值接收者.
正确的做法是应该基于这个类型的本质.
比如时间操作, 应该用值接收者, 返回一个新的时间值; 文件操作应该使用指针接收者, 始终操作的是底层的文件本身.