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 " ...
随机推荐
- Android Studio配置openvc
最近项目中需要用到opencv,于是就研究了一下怎么在Android studio中配置opencv,记录一下,免得以后还会使用. 一.因为本人Android Studio是4.1的,网上资料大多是3 ...
- 【uniapp 开发】字符串工具类 StringUtil
替换字符串中的所有 "***" 子串 var str='Is this all there is'; var subStr=new RegExp('is','ig');//创建正则 ...
- 在Android中区分点击和滑动操作
转自:http://blog.csdn.net/do168/article/details/51587933 最近在写一个图片浏览安卓应用,想要弄成全屏显示,只在单击时显示工具栏和状态栏,在触摸滑动时 ...
- java基础-多线程 等待唤醒机制
/** * @param args * 等待唤醒机制 */ public static void main(String[] args) { final Printer p = new ...
- jQuery实现数字时钟
运行效果: 源代码: 1 <!DOCTYPE html> 2 <html lang="zh"> 3 <head> 4 <meta char ...
- EMS邮箱数据库全局监控设置
案例任务:监控TestDB01邮箱数据库的所有邮件,监控邮箱为用户"王淑江"的邮箱. 1.EMS全局监控设置 使用PowerShell完成操作:"王淑江"监控T ...
- Hash冲突以及解决
哈希函数:它把一个大范围的数字哈希(转化)成一个小范围的数字,这个小范围的数对应着数组的下标.使用哈希函数向数组插入数据后,这个数组就是哈希表. 冲突 当冲突产生时,一个方法是通过系统的方法找到数组的 ...
- 微信小程序--设置和获取剪切板内容
设置 wx.setClipboardData // 复制功能 获取 wx.getClipboardData // 粘贴功能 let _this = this wx.setClipbo ...
- partOne测试收获总结
测试收获总结 执行类中构造多个方法,将各个功能分解出来,将大的,复杂的问题转化成小的,简单的问题,来进行处理,正所谓复杂问题简单化,简单问题流程化.大道至简编程精益.现总结编程中的一些问题,①在J ...
- JS/TS项目里的Module都是什么?
摘要:在日常进行JS/TS项目开发的时候,经常会遇到require某个依赖和module.exports来定义某个函数的情况.就很好奇Modules都代表什么和有什么作用呢. 本文分享自华为云社区&l ...