Golang的值类型receiver和指针类型receiver

Golang的值类型和指针类型receiver一直让我比较混淆,在此做几个试验备忘

先看指针类型的receiver:

package main
import (
"fmt"
)
type BasicEvent struct {
EventId int
}
func (ev *BasicEvent) updateEventID(id int) {
ev.EventId = id
}
func main() {
ev1 := &BasicEvent{EventId: 1}
fmt.Printf("before update id = %d\n", ev1.EventId)
ev1.updateEventID(2)
fmt.Printf("After update id = %d\n", ev1.EventId)
ev2 := BasicEvent{EventId: 1}
fmt.Printf("before update id = %d\n", ev2.EventId)
ev2.updateEventID(2)
fmt.Printf("After update id = %d\n", ev2.EventId)
}

输出的结果是:

before update id = 1

After update id = 2

before update id = 1

After update id = 2

由此可见,不管调用的时候是个值还是指针,只要是方法的receiver是指针类型,都能够修改调用者的内部状态。我估计这个时候是Go自动做了指针转换。


再看值类型的receiver:

package main
import (
"fmt"
)
type BasicEvent struct {
EventId int
}
func (ev BasicEvent) updateEventID(id int) {
ev.EventId = id
}
func main() {
ev1 := &BasicEvent{EventId: 1}
fmt.Printf("before update id = %d\n", ev1.EventId)
ev1.updateEventID(2)
fmt.Printf("After update id = %d\n", ev1.EventId)
ev2 := BasicEvent{EventId: 1}
fmt.Printf("before update id = %d\n", ev2.EventId)
ev2.updateEventID(2)
fmt.Printf("After update id = %d\n", ev2.EventId)
}

输出的结果是:

before update id = 1

After update id = 1

before update id = 1

After update id = 1

由此可见,不管调用的时候是个值还是指针,只要是方法的receiver是值类型,都无法改变调用者的内部状态。


总是可见,主要关注的点是方法定义的时候到底receiver是指针还是值类型,如果receiver是指针,内部状态才可以改。


另外,关于关于传入参数是否可改的问题

package main
import (
"fmt"
)
type BasicEvent struct {
EventId int
}
func updateEventIDByPointer(ev *BasicEvent, newID int) {
ev.EventId = newID
}
func updateEventIDByValue(ev BasicEvent, newID int) {
ev.EventId = newID
}
func main() {
ev1 := &BasicEvent{EventId: 1}
fmt.Printf("before update id = %d\n", ev1.EventId)
updateEventIDByPointer(ev1, 2)
fmt.Printf("After update id = %d\n", ev1.EventId)
ev2 := BasicEvent{EventId: 1}
fmt.Printf("before update id = %d\n", ev2.EventId)
updateEventIDByValue(ev2, 2)
fmt.Printf("After update id = %d\n", ev2.EventId)
ev3 := &BasicEvent{EventId: 1}
fmt.Printf("before update id = %d\n", ev3.EventId)
updateEventIDByValue(*ev3, 2)
fmt.Printf("After update id = %d\n", ev3.EventId)
ev4 := BasicEvent{EventId: 1}
fmt.Printf("before update id = %d\n", ev4.EventId)
updateEventIDByPointer(&ev4, 2)
fmt.Printf("After update id = %d\n", ev4.EventId)
}

结果如下:

before update id = 1

After update id = 2

before update id = 1

After update id = 1

before update id = 1

After update id = 1

before update id = 1

After update id = 2

前两个比较好理解。第三个值得注意的是,对指针解引用会创建另一个值对象,所以无法改变内部状态。第四个也好说,取地址后得到了原始值对象的引用,所以可以修改内部状态。


关于如何在值类型和指针类型的receiver之间做选择,可以参考

https://github.com/golang/go/wiki/CodeReviewComments#receiver-type

转载于:https://my.oschina.net/miros/blog/405509

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值