文档章节

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

miros
 miros
发布于 2015/04/23 14:41
字数 650
阅读 70
收藏 0
点赞 0
评论 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

golang中method的传值与传地址

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

alexstocks ⋅ 2015/01/23 ⋅ 1

Golang:方法

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

与蟒唯舞 ⋅ 01/05 ⋅ 0

Golang之面向对象

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

xumaojun ⋅ 01/30 ⋅ 0

Go语言之方法详解

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

棋帅小七 ⋅ 2017/12/24 ⋅ 0

Go基础编程:面向对象—方法

1 概述 在面向对象编程中,一个对象其实也就是一个简单的值或者一个变量,在这个对象中会包含一些函数,这种带有接收者的函数,我们称为方法(method)。 本质上,一个方法则是一个和特殊类型关...

tennysonsky ⋅ 2017/12/28 ⋅ 0

Golang锁失效原因之value receiver

先说结论 golang中,值类型在作为方法参数和方法的接受者的时候,都需要进行值的拷贝,所以,使用值类型的时候要多加注意。对于方法的接受者,如果方法需要修改接受者的某个变量值,那么就应...

一条大河波浪宽 ⋅ 2016/11/27 ⋅ 0

『Go 语言学习专栏』-- 第四期

大家好,我是谢伟,是一名程序员。 本专栏的主旨是:梳理 Golang 知识,力求从初级水平提升至中级水平。 同时将一些符合人性的编程经验和好的编程方法,分享给大家。 希望对大家有帮助。 本节...

谢小路 ⋅ 05/10 ⋅ 0

go方法的深入探究(7.21增补)

1)哪些类型可以有方法: 1)只能对命名类型和命名类型的指针编写方法; 2)不能对接口类型和接口类型的指针编写方法; 3)只能在定义命名类型的那个包编写其方法。 2)receiver是值的方法,...

刘地 ⋅ 2014/07/19 ⋅ 4

go的隐藏字段的方法

虽然go的编译器会给receiver为值的方法自动实现一个receiver为指针的同名方法,但go的编译器并没有足够聪明 对于包含隐藏字段的某类型,其指针调用隐藏字段的方法是,只会考虑隐藏字段的类型...

刘地 ⋅ 2013/07/29 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

前台对中文编码,后台解码

前台:encodeURI(sbzt) 后台:String param = URLDecoder.decode(sbzt,"UTF-8");

west_coast ⋅ 35分钟前 ⋅ 0

VS2015配置并运行汇编(一步一步照图做)【vs2017的链接在最后】

前言 我是上学期学的汇编,因为有vs又不想用课上教的麻烦的dosbox以及masm32,但是一直没找到高亮插件和能调试的(难在运行不了而找不到答案上,出现的错误在最后放出,还请先达们不吝指点)...

simpower ⋅ 45分钟前 ⋅ 0

一起读书《深入浅出nodejs》-node模块机制

node 模块机制 前言 说到node,就不免得提到JavaScript。JavaScript自诞生以来,经历了工具类库、组件库、前端框架、前端应用的变迁。通过无数开发人员的努力,JavaScript不断被类聚和抽象,...

小草先森 ⋅ 48分钟前 ⋅ 0

Java桌球小游戏

其实算不上一个游戏,就是两张图片,不停的重画,改变ball图片的位置。一个左右直线碰撞的,一个有角度碰撞的。 左右直线碰撞 package com.bjsxt.test;import javax.swing.*;import j...

森林之下 ⋅ 54分钟前 ⋅ 0

你真的明白RPC 吗?一起来探究 RPC 的实质

你真的明白RPC 吗?一起来探究 RPC 的实质 不论你是科班出身还是半路转行,这么优秀的你一定上过小学语文,那么对扩句和缩句你一定不陌生。缩句就是去除各种修饰提炼出一句话的核心,而不失基...

AI9o後 ⋅ 56分钟前 ⋅ 0

z-index设置失效?

今天碰到了一个问题,就是在给li设置提示框的时候,有用到遮罩效果,本来想把对应的出现在最顶层,可是不管将li设置的z-index值设为多大,li都没有出现在遮罩层之上。 我在网上查了z-index设...

IrisHunag ⋅ 今天 ⋅ 0

CyclicBarrier、CountDownLatch以及Semaphore使用及其原理分析

CyclicBarrier、CountDownLatch以及Semaphore是Java并发包中几个常用的并发组件,这几个组件特点是功能相识很容易混淆。首先我们分别介绍这几个组件的功能然后再通过实例分析和源码分析其中设...

申文波 ⋅ 今天 ⋅ 0

Java对象的序列化与反序列化

Java对象的序列化与反序列化

Cobbage ⋅ 今天 ⋅ 0

Sqoop

1.Sqoop: 《=》 SQL to Hadoop 背景 1)场景:数据在RDBMS中,我们如何使用Hive或者Hadoop来进行数据分析呢? 1) RDBMS ==> Hadoop(广义) 2) Hadoop ==> RDBMS 2)原来可以通过MapReduce I...

GordonNemo ⋅ 今天 ⋅ 0

全量构建和增量构建的区别

1.全量构建每次更新时都需要更新整个数据集,增量构建只对需要更新的时间范围进行更新,所以计算量会较小。 2.全量构建查询时不需要合并不同Segment,增量构建查询时需要合并不同Segment的结...

无精疯 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部