golang 方法接收者
- [定义]: golang的方法(Method)是一个带有receiver的函数Function,Receiver是一个特定的struct类型,当你将函数Function附加到该receiver, 这个方法Method就能获取该receiver的属性和其他方法。
- [面向对象]: golang方法Method允许你在类型上定义函数,是一个面向对象的行为代码, 这也有一些益处:同一个package可以有相同的方法名, 但是函数Function却不行。
func (receiver receiver_type) some_func_name(arguments) return_values
从应用上讲,方法接受者分为值接收者,指针接收者,初级golang学者可能看过这两个接收者实际表现, 但是一直很混淆,很难记忆。
本次我们使用地址空间的角度来剖析实质,强化记忆。
值类型方法接收者
值接受者: receiver是struct等值类型。
下面定义了值类型接受者Person, 尝试使用Person{}, &Person{}去调用接受者函数。
package main
import "fmt"
type Person struct {
name string
age int
}
func (p Person) say() {
fmt.Printf("I (%p) ma %s, %d years old \n",&p, p.name,p.age)
}
func (p Person) older(){ // 值类型方法接受者: 接受者是原类型值的副本
p.age = p.age +1
fmt.Printf("I (%p) am %s, %d years old\n", &p, p.name,p.age)
}
func main() {
p1 := Person{name: "zhangsan", age: 20}
p1.older()
p1.say()
fmt.Printf("I (%p) am %s, %d years old\n",&p1, p1.name,p1.age)
p2 := &Person{ name: "sili", age: 20}
p2.older() // 即使定义的是值类型接受者, 指针类型依旧可以使用,但我们传递进去的还是值类型的副本
p2.say()
fmt.Printf("I (%p) am %s, %d years old\n",p2, p2.name,p2.age)
}
尝试改变p1=Person{},p2=&Person{}的字段值:
I (0xc000098078) am zhangsan, 21 years old
I (0xc000098090) ma zhangsan, 20 years old
I (0xc000098060) am zhangsan, 20 years old
I (0xc0000980c0) am sili, 21 years old
I (0xc0000980d8) ma sili, 20 years old
I (0xc0000980a8) am sili, 20 years old
p1=Person{} 未能修改原p1的字段值; p2=&Person{}也未能修改原p2的字段值。
- 通过Person{}值去调用函数, 传入函数的是原值的副本, 这里通过第一行和第三行的
%p印证 (%p:输出地址值, 这两个非同一地址)。 - 即使定义的是值类型接收者,指针类型依旧可以调用函数, 但是传递进去的还是值类型的副本。
带来的效果是:对值类型接收者内的字段操作,并不影响原调用者。
指针类型接受者
方法接收者也可以定义在指针上,任何尝试对指针接收者的修改,会体现到调用者。
package main
import "fmt"
type Person struct{
name string
age int
}
func (p Person) say(){
fmt.Printf("I (%p) am %s, %d years old\n", &p, p.name,p.age)
}
func (p *Person) older(){ // 指针接受者,传递函数内部的是原类型值(指针), 函数内的操作会体现到原指针指向的空间
p.age = p.age +1
fmt.Printf("I (%p) am %s, %d years old\n", p, p.name,p.age)
}
func main() {
p1 := Person{"zhangsan",20}
p1.older() // 虽然定义的是指针接受者,但是值类型依旧可以使用,但是会隐式传入指针值
p1.say()
fmt.Printf("I (%p) am %s, %d years old\n", &p1, p1.name,p1.age)
p2:= &Person{"sili",20}
p2.older()
p2.say()
fmt.Printf("I (%p) am %s, %d years old\n", p2, p2.name,p2.age)
}
尝试改变p1= Person{}, p2=&Person{}字段值
I (0xc000098060) am zhangsan, 21 years old
I (0xc000098078) am zhangsan, 21 years old
I (0xc000098060) am zhangsan, 21 years old
I (0xc000098090) am sili, 21 years old
I (0xc0000980a8) am sili, 21 years old
I (0xc000098090) am sili, 21 years old
p1=Person{} 成功修改字段值,p2=&Person{}也成功修改字段值。
- 通过p1也可以调用指针函数接收者, 但是实际会隐式传递指针值。
- 指针接收者,入参是原指针值,函数内的操作会体现到原调用者。
带来的效果: 任何对指针接收者的修改会体现到 原调用者。
什么时候使用指针接收者
- 需要对接受者的变更能体现到原调用者
- 当struct占用很大内存,最好使用指针接受者,否则每次调用接受者函数 都会形成struct的大副本
golang方法的几种姿势
接上例子:
- 将接收者函数当扩展函数
Person.say(p1)
(*Person).older(p2)
依旧是 值类型/指针类型方法接收者的效果。
I (0xc0000040d8) am zhangsan, 21 years old
I (0xc0000040a8) am sili, 22 years old
这种姿势相对于面向对象的接收者不常见。
- golang 方法链条
func (p Person) printName() Person{
fmt.Printf("Name:%s", p.Name)
return p
}
- Non_struct类型golang方法
type myFloat float64
func (m myFloat) ceil() float64 {
return math.Ceil(float64(m))
}
以上是有态度的马甲记录的有关golang 方法接收者的全部用法,通过%p,我们探究了值类型/指针接收者的调用原理。
golang 方法接收者的更多相关文章
- Golang 方法接收者是值还是指针问题
对于普通结构体作为接收者,值和指针并没有区别. (以下代码摘抄自Go In Action 中文版) type defaultMatcher struct{} // 方法声明为使用 defaultMat ...
- golang方法详解
Go 语言 类型方法是一种对类型行为的封装 .Go 语言的方法非常纯粹, 可以看作特殊类型的函数,其显式地将对象实例或指针作为函数的第一个参数,并且参数可以自己指定,而不强制要求一定是 this或se ...
- golang指针接收者和值接收者方法调用笔记
初学go时很多同学会把 值接收者 和 指针接收者 的方法相互调用搞混淆,好多同学都只记得指针类型可以调用值接收者方法和指针接收者方法,而值类型只能调用值接收者方法,其实不然,在某些情况下,值类型也是可 ...
- Golang对方法接收者变量的自动“取引用”和“解引用”
原文:https://blog.csdn.net/u014633283/article/details/83826413 --------------------------------------- ...
- Golang 方法method
方法method Go中虽没有class,但依旧有method 通过显示说明receiver来实现与某个类型的结合 只能为同一个包中的类型定义方法 receiver可以是类型的值或者指针 不存在方法重 ...
- golang方法和接口
一. go方法 go方法:在函数的func和函数名间增加一个特殊的接收器类型,接收器可以是结构体类型或非结构体类型.接收器可以在方法内部访问.创建一个接收器类型为Type的methodName方法. ...
- (11)Go方法/接收者
方法和接收者 Go语言中的方法(Method)是一种作用于特定类型变量的函数.这种特定类型变量叫做接收者(Receiver).接收者的概念就类似于其他语言中的this或者 self. 方法的定义格式如 ...
- golang 方法内部定义子方法及调用
package main import ( "fmt" "reflect" ) func out(ch chan int) { <-ch fmt.Prin ...
- golang 方法
方法: 在函数声明时,在其名字之前放上一个变量,即是一个方法.这个附加的参数会将该函数附 加到这种类型上,即相当于为这种类型定义了一个独占的方法. package main import " ...
随机推荐
- Java/C++实现观察者模式--股票价格
当股票的价格上涨或下降5%时,会通知持有该股票的股民,当股民听到价格上涨的消息时会买股票,当价格下降时会大哭一场. 类图: Java代码: public class Investor implemen ...
- java中“类”和“对象”到底有什么联系
4.object和Class配合工作原理 [新手可忽略不影响继续学习] Class是"类"的意思,是抽象的,并没有具体的说是哪个东西.而object是具体的,实实在在存在的一 ...
- JS判断数组中的对象的每一个值不能为空
方法一:使用every()函数,此函数不怎么常用,想要了解更多请自查 //表格 evaluateData为表格的数据 <el-table id="out-table3" :d ...
- FreeRTOS学习记录--任务创建函数详解
开局一张图.一步一步分析就好. (一)什么是任务? 在多任务系统中,我们按照功能不同,把整个系统分割成一个个独立的,且无法返回的函数,这个函数我们称为任务:任务包含几个属性:任务堆栈,任务函数.任务控 ...
- SpringMVC-获得Restful风格的参数
使用@PathVariable注解:接收请求路径中占位符的值 @RequestMapping("/report18/{username}") @ResponseBody publi ...
- Codeforces Round #767 (Div. 2)——B. GCD Arrays
B. GCD Arrays 题源:https://codeforces.com/contest/1629/problem/B 题目大意 给出一段区间[l, r],可以进行操作(把任意两个数拿出来,把他 ...
- partTwo自动出题程序第二阶段
(1)题目避免重复: (2)可定制(数量/打印方式): 代码实现 import java.util.ArrayList;import java.util.Random;import java.util ...
- DOM 对象的重点核心
概述 : 文档对象模型(Document Object Model,简称DOM ),是W3C组织推荐的处理可扩展标记语言 (HTML或者XML)的标准编程接口. W3C已经定义了一系列的DOM接口, ...
- JavaWeb和WebGIS学习笔记(七)——MapGuide Open Source安装、配置以及MapGuide Maestro发布地图——超详细!目前最保姆级的MapGuide上手指南!
JavaWeb和WebGIS学习笔记(七)--MapGuide Open Source安装.配置以及MapGuide Maestro发布地图 超详细!目前最保姆级的MapGuide上手指南! 系列链接 ...
- python学习-Day36
目录 进程 进程间通信 队列(multiprocess.Queue) 概念 Queue的实例q具有以下方法: 消息队列 生产者消费者模型 实现生产者消费者模型三要素: 线程理论 线程概念 线程存在的意 ...