文档章节

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

miros
 miros
发布于 2015/04/23 14:41
字数 650
阅读 85
收藏 0

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

© 著作权归作者所有

共有 人打赏支持
miros
粉丝 0
博文 4
码字总数 4259
作品 0
成都
golang sort 包使用,及三个简单排序算法冒泡,插入,选择 练习

sort 包的核心类型是 sort.Interface: type Interface interface { // Len is the number of elements in the collection. Len() int // Less reports whether the element with // index i......

yujian0231
2015/01/22
0
0
golang中method的传值与传地址

golang中,struct的method的形式如下: func (r ReceiverType) funcName(parameters) (results) 如果想要修改struct的成员的值,method被定义时候其ReceiverType必须是struct形式。如果Recei...

alexstocks
2015/01/23
0
1
Golang:方法

什么是方法 一个方法只是一个函数,它有一个特殊的接收者(receiver)类型,该接收者放在 关键字和函数名之间。接收者可以是结构体类型或非结构体类型。可以在方法内部访问接收者。 可以通过...

与蟒唯舞
01/05
0
0
Golang之面向对象

一、method 带有接收者的函数,称之为method。 假设定义了一个struct叫长方形,现在要计算它的面积,那么按照面向过程的思路会如下实现: packeage main import "fmt" type Rectange struct ...

xumaojun
01/30
0
0
Go语言之方法详解

方法是与对象实例绑定的特殊函数。 用于维护和展示对象自身的状态。对象是内敛的。普通函数则专注与算法流程,通过接受参数来完成特定的逻辑运算,并返回最终结果,方法是有关联状态的,函数...

棋帅小七
2017/12/24
0
0

没有更多内容

加载失败,请刷新页面

加载更多

rabbitmq学习(一)

RabbitMQ是目前非常热门的一款消息中间件,具有高可靠、易拓展、高可用及丰富的功能 1.什么是消息中间件 消息是指在应用间传送的数据。包含文本字符串、JSON、内嵌对象 消息队列中间件(消息...

hensemlee
30分钟前
1
0
学习设计模式——原型模式

1. 认识原型模式 1. 定义:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。 2. 结构: Prototype:声明一个克隆自身的接口,用来约束想要克隆自己的具体实现类,要求这些类...

江左煤郎
36分钟前
1
0
观察者模式

观察者模式的套路 有如下角色: 事件,比如修改,用户点击; 事件队列,触发事件之后,会把事件一个一个放入事件队列 监听器,采用某种方式(一般是轮询,或者io阻塞机制),来判断事件队列是否有新的未...

黄威
39分钟前
1
0
线程安全策略

四个线程安全策略 线程限制: 一个被线程限制的对象,由线程独占,并且只能被占有它的线程修改 共享只读: 一个共享只读的对象,在没有额外同步的情况下,可以被多个线程并发访问,但是任何线...

Ala6
46分钟前
2
0
Dubbo (三)源码分析 —— 架构原理

1 核心功能 首先要了解Dubbo提供的三大核心功能: Remoting:远程通讯 提供对多种NIO框架抽象封装,包括“同步转异步”和“请求-响应”模式的信息交换方式。 Cluster: 服务框架 提供基于接口方...

小刀爱编程
48分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部