6.方法(go语言学习笔记)


目录

  1. 定义
  2. 匿名字段
  3. 方法集
  4. 表达式

1. 定义

  1. 方法是与对象实例绑定的特殊函数。
  2. 方法是面向对象编程的基本概念,用于维护和展示对象的自身状态。对象是内敛的,每个实例对象都有各自不同的独立特征,以属性和方法来暴露对外通信接口。
  3. 普通函数则专注于算法流程,通过接收参数来完成特定逻辑运算,并返回最终结果。
  4. 换句话说,方法是有关联状态的,而函数通常没有。
  5. 方法和函数定义的语法区别在于前者有前置实例接收参数,编译器以此确定方法所属类型。在某些语言中,尽管没有显示定义,但会在调用时隐式传递this实例参数。
  6. 可以为当前包,以及除接口和指针以外的任何类型定义方法。
type N intfunc (n N) toString() string {return fmt.Sprintf("%#x", n)
}func main() {var a N = 25println(a.toString())
}
  1. 方法同样不支持重载。接收参数名没有限制,按照惯例会选用简短有意义的名称(不推荐用this,self)。如方法内部并不引用实例,可省略参数名,仅保留类型。
type N intfunc (N) test() {println("hi!")
}
  1. 方法可看作特殊的函数,那么receiver的类型自然可以是基础类型或指针类型。这会关系到调用时对象实例是否被复制。
type N intfunc (n N) value() {n++fmt.Printf("v:%p,%v\n", &n, n)}func (n *N) pointer() {(*n)++fmt.Printf("v:%p,%v\n", n, *n)
}func main() {var a N = 25a.value()fmt.Printf("a: %p,%v\n",&a,a)a.pointer()fmt.Printf("a: %p,%v\n",&a,a)
}
  1. 输出
v: 0xc000018090,26
a: 0xc000018088,25
v: 0xc000018088,26
a: 0xc000018088,26
  1. 可使用实例值或指针调用方法,编译器会根据方法receiver类型自动在基础类型和指针类型间转换。
func main() {var a N = 25p := &aa.value() //26,但a的值没变p.pointer() // a=26,p是a的地址p.value()   //27, 但a的值还是26p.pointer() //a=27
}
  1. 输出
v: 0xc0000a4010,26
v: 0xc0000a4008,26
v: 0xc0000a4040,27
v: 0xc0000a4008,27
  1. 不能用多级纸质调用方法。
  2. 指针类型的receiver必须是合法指针(包括nil),或能获取示例地址。
  3. 如何选择方法的receiver类型?
    1. 要修改实例状态,用 *T
    2. 无需修改状态的小对象或固定值,建议用 T
    3. 大对象建议用 *T,以减少复制成本。
    4. 引用类型、字符串、函数等指针包装对象,直接用T
    5. 若包含 Mutex 等同步字段,用 *T,避免因复制造成锁操作无效
    6. 其他无法确定的情况,都用 *T

2. 匿名字段

  1. 可以像访问匿名字段成员那样调用其方法,由编译器负责查找。
type data struct {sync.Mutexbuf [1024]byte
}func main() {d := data{}d.Lock() //编译器会处理为 sync.(*Mutex).Lock() 调用defer d.Unlock()
}
  1. 方法也有同名隐蔽问题,但利用这种特性,可以实现类似覆盖(override)操作。
type user struct{}type manager struct {user
}func (user) toString() string {return "user"
}func (m manager) toString() string  {return m.user.toString()+"; manager"
}func main() {var m managerprintln(m.toString())println(m.user.toString())
}
  1. 输出
user; manager
user

3. 方法集

  1. 类型有一个与之相关的方法集(method set),这决定了它是否实现了某个接口

    1. 类型T方法集包含所有receiver T方法
    2. 类型 *T 方法集包含所有 receiver T+ *T方法
    3. 匿名嵌入S,T方法集包含所有receiver S方法
    4. 匿名嵌入 *S,T方法集包含所有receiver S+*S 方法。
    5. 匿名嵌入 S 或 *S,*T方法集包含所有 receiver S+ *S 方法。
  2. 方法集仅影响接口实现和方法表达式转换,与通过实例或实例指针调用方法无关。实例并不使用方法集,而是直接调用。
  3. 很显然,匿名字段是为方法集准备的。否则,完全没必要为少写个字段名而大费周章。
  4. 面向对象的三大特征:封装,继承,多态。Go仅实现了部分特征,更倾向于”组合优于继承“思想。
  5. 将模块分解成互相独立的更小单元,分别处理不同方面的需求,最后以匿名嵌入方式组合在一起,共同实现对外接口。
  6. 其简短一致的调用方式,更是隐藏了内部实现细节。

4. 表达式

  1. 方法和函数一样,除直接调用,还可以赋值给变量,作为参数传递。依照具体引用方式的不同,可分为expression和value两种状态

1. Method Expression

  1. 通过类型引用的 method expression 会被还原为普通函数样式,receiver是第一参数,调用时必须显式传参。至于类型,可以是T 或者 *T,只要目标方法存在于改类型方法集中即可。
type N intfunc (n N) test() {fmt.Printf("test.n: %p,%d\n", &n, n)
}func main() {var n N = 25fmt.Printf("main.n: %p, %d\n",&n,n)f1 := N.test  // func(n N)f1(n)f2 := (*N).test  // func(n *N)f2(&n)       //按方法集中的签名传递正确类型的参数
}
  1. 输出
main.n:0xc000018088, 25
test.n: 0xc0000180a0,25
test.n: 0xc0000180b0,25
  1. 尽管*N方法集包装的test方法receiver类型不同,但编译器会保证按原定义类型拷贝传值。
  2. 当然,也可直接表达式方法调用。
func main() {var n N = 25N.test(n)(*N).test(&n)
}

2. Method Value

  1. 基于实例或指针引用的method value,参数前面不会改变,依旧按正常方式调用。
  2. 但当method value被赋值给变量或者参数传递时,会立即计算并复制该方法执行所需的receiver对象,与其绑定,以便在稍后执行时,能隐式传入receiver参数。
func main() {var n N = 100p := &nn++f1 := n.testn++f2 := p.testn++fmt.Printf("main.n:%p, %v\n",p,n)f1()f2()
}
  1. 输出
main.n:0xc000096008, 103
test.n: 0xc000096020,101
test.n: 0xc000096030,102
  1. 编译器会为method value生成一个包装函数,实现间接调用。至于receiver复制,和闭包的实现方法基本相同,打包成funcval,经由DX寄存器传递。
  2. 当然,如果目标方法的receiver是指针类型,那么被复制的仅是指针。
type N intfunc (n *N) test() {fmt.Printf("test.n: %p,%d\n", n, *n)
}func main() {var n N = 100p := &nn++f1 := n.testn++f2 := p.testn++fmt.Printf("main.n:%p, %v\n",p,n)f1()f2()
}
  1. 输出
main.n:0xc000096008, 103
test.n: 0xc000096008,103
test.n: 0xc000096008,103
  1. 只要receiver参数类型正确,使用nil同样可以执行。

6.方法(go语言学习笔记)相关推荐

  1. C语言如何加缓冲,C语言学习笔记之输出缓冲

    在c语言中经常用到输出函数printf,当我们像往常一样在输出函数中输入我们的想要的输出的东西后加\n换行 验证结果如我们输出的一样 如果我们在后面加入死循环会不会出现这些语句呢 结果卡死了,可还是输 ...

  2. c语言中void arrout,c语言学习笔记(数组、函数

    <c语言学习笔记(数组.函数>由会员分享,可在线阅读,更多相关<c语言学习笔记(数组.函数(53页珍藏版)>请在人人文库网上搜索. 1.数组2010-3-29 22:40一维数 ...

  3. c语言学习笔记【结构体02】结构体指针变量与结构体变量的函数参数,C语言学习笔记结构体02结构体指针变量与结构体变量的函数参数.docx...

    C 语言学习笔记[结构体02]结构体指针变量与结构体变量 的函数参数 C 语言学习笔记之结构体指针变量一提指针,那可 是 C 语言的核心了,有多少学子曾拜倒在指针的脚下.单纯的说指针,其实并不难,但是 ...

  4. go get 拉取指定版本_go语言学习笔记-基础知识-3

    相关文档 go语言学习笔记-目录 1.简介 1.1 什么是GO Go 是一个开源的编程语言,它能让构造简单.可靠且高效的软件变得容易.Go是从2007年末由Robert Griesemer, Rob ...

  5. c语言如何宏定义枚举型结构体,C语言学习笔记--枚举结构体

    枚举 枚举是一种用户定义的数据类型,它用关键字enum以如下语法格式来声明: enum 枚举类型名字 {名字0,名字1,...,名字n}: 枚举类型名字通常并不真的使用,要用的是大括号里面的名字,因为 ...

  6. C语言学习笔记-P1 初识C语言(2)

    C语言学习笔记-P1 初识C语言(2) C语言学习笔记-P1 初识C语言(2) 一.常量 1.字面常量 2.const修饰的常变量 3.#define定义的标识符常量 3.枚举常量 二.字符串+转义字 ...

  7. C语言学习笔记-P1 初识C语言(1)

    C语言学习笔记-P1 初识C语言(1) P1 初识C语言(1) 一.什么是C语言 1.定义 2.发展 二.第一个C语言程序 Hello World 三.数据类型 四.变量,常量 未完待续!!! P1 ...

  8. R语言学习笔记(1~3)

    R语言学习笔记(1~3) 一.R语言介绍 x <- rnorm(5) 创建了一个名为x的向量对象,它包含5个来自标准正态分布的随机偏差. 1.1 注释 由符号#开头. #函数c()以向量的形式输 ...

  9. C++语言学习笔记15:Clean 垃圾清理插件

    C++语言学习笔记15:Clean 垃圾清理插件 对话框 STET1 图片切换功能 导入位图资源 插入图片控件并修改属性 添加消息处理函数 step2 开发思路及类关系图 step3 添加控件及MFC ...

最新文章

  1. 社会保险省内转移需要什么手续或过程?
  2. Spring Cloud Stream如何消费自己生产的消息
  3. Boost:boost::bimaps::list_of的测试程序
  4. python 指定端口读取网站_Python实现局域网指定端口扫描
  5. Fiori Launchpad server side config json
  6. Windows 11 小技巧- 安装
  7. 课后作业-结队编程项目进度-贪吃蛇
  8. LVM逻辑卷管理学习
  9. Django:数据迁移不生成auth相关表
  10. 学习记录之显示屏语言模块确定,星瞳学习
  11. QIODevice::write : device not open
  12. QS最新大学排名惹争议:深大南科大再获认可,上海大学超华科,人大校友心里最苦...
  13. python拟合log函数得出公式
  14. 印度行——印度软件公司的印象
  15. 二十八条改善 ASP 性能和外观的技巧
  16. CSS组件_0 燕尾
  17. python模拟比赛测试胜率
  18. Matlab中hold函数使用
  19. w7计算机配置在哪里打开,win7的运行在哪里打开 win7打开运行的方法【图文】
  20. [渝粤教育] 中国地质大学 钢结构 复习题 (2)

热门文章

  1. oracle学习篇一:sqlplus常用命令
  2. jQuery实现右上角点击后滑下来的竖向菜单
  3. [转]VSTO Office二次开发应用程序键盘鼠标钩子
  4. 牛客 - Elo mountains(AC自动机+可持久化数组优化)
  5. 2020ICPC(上海) - Sum of Log(数位dp)
  6. (转)Splay伸展树模板
  7. HDU - 5475 An easy problem(线段树)
  8. apache madlib 教程_Apache顶级开源项目——机器学习库MADlib简介与应用实例
  9. python遍历文件对象_Python文件常见操作实例分析【读写、遍历】
  10. 电脑卡顿不流畅怎么解决_如何解决因电脑内存容量不足引起的卡顿?