Golang的值类型receiver和指针类型receiver
miros · · 5253 次点击 · · 开始浏览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
前两个比较好理解。第三个值得注意的是,对指针解引用会创建另一个值对象,随意无法改变内部状态。第四个也好说,取地址后得到了原值对象的引用,所以可以修改内部状态。
有疑问加站长微信联系(非本文作者)
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
关注微信- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码` - 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传
收入到我管理的专栏 新建专栏
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
前两个比较好理解。第三个值得注意的是,对指针解引用会创建另一个值对象,随意无法改变内部状态。第四个也好说,取地址后得到了原值对象的引用,所以可以修改内部状态。