-
- GO语言学习笔记-函数篇 Study for Go ! Chapter three - Function
- GO语言学习笔记-数据篇 Study for Go ! Chapter four - Data
- GO语言学习笔记-方法篇 Study for Go ! Chapter five - Method
- GO语言学习笔记-接口篇 Study for Go ! Chapter six - Interface
- GO语言学习笔记-并发篇 Study for Go ! Chapter seven - Concurrency
- GO语言学习笔记-包结构篇 Study for Go ! Chapter eight - Package Structure
- GO语言学习笔记-反射篇 Study for Go ! Chapter nine - Reflect
- GO语言学习笔记-测试篇 Study for Go ! Chapter ten- Test
- GO语言学习笔记-工具链篇 Study for Go ! Chapter eleven - Tool Chain
2023-03-09
1. Initialization
-
方法是与对象实例绑定特殊函数
-
方法是面向对象编程的基本概念,用于维护和展示对象的自身状态。
-
对象是内敛的,每个实例都有各自不同的独立特征,以属性和方法来暴露对外通信接口
-
普通函数则专注于算法流程,通过接受参数来完成特定逻辑运算,并返回最终结果。
-
方法是有关联状态的,而函数则通常没有
-
-
在某些语言里,尽管没有显式定义,但会在调用时隐式传递 this 实例参数
-
可以为当前包,以及除接口和指针以外的任何类型定义方法
-
方法同样不支持重载 (overload),receiver 参数名没有限制,按惯例会选用简短有意义的名称(不推荐使用 this、self)
-
如方法内部并不引用实例,可省略参数名,仅保留类型
-
方法可以看作特殊的函数,那么 receiver 的类型自然可以是基础类型或指针类型。这会关系到调用时对象实例是否被复制
-
可使用实例值或指针调用方法,编译器会根据方法 receiver 类型自动在基础类型和指针类型间转换
-
不能使用多级指针调用方法
-
指针类型的 receiver 必须是合法指针 (包括 nil ),或能获取实例地址
How to choice receiver type ?
-
要修改实例状态,用 *T
-
无需修改状态的小对象或固定值,建议用 T
-
大对象建议用 *T,以减少复制成本
-
引用类型、字符串、函数等指针包装对象,直接用 T
-
若包含 Mutex 等同步手段,用 *T 避免因复制造成锁操作无效
-
其他无法确定的情况都用 *T
2. 匿名字段
-
可以像访问匿名字段成员那样调用其方法,由编译器负责查找
-
方法也会有同名遮蔽问题,但利用这种特性,可实现类似覆盖(override)操作
-
尽管能直接访问匿名字段的成员和方法,但它们依然不属于继承关系
3. 方法集
-
类型有一个与之相关的方法集 ( method set),这决定了它是否实现某个接口
-
类型 T 方法集包含所有 receiver T 方法
-
类型 *T 方法集包含所有 receiver T + *T 方法
-
匿名嵌入 S,T 方法包含所有 receiver S 方法
-
匿名嵌入 * S,T 方法集包含所有 receiver S + *S方法
-
匿名嵌入 S 或 *S, *T 方法集包含所有 receiver S + *S 方法
可利用反射 ( reflect )测试这些规则
-
-
方法集仅影响接口实现和方法表达式转换,与通过实例或实例指针调用方法无关。
-
实例并不使用方法集而是直接调用
-
匿名字段就是为方法集准备的,否则完全没必要为少写个字段名而大费周章
Attention
-
面向对象的三大特征 “ 封装 ”、“ 继承 ” 和 “ 多态 ”,golang 仅实现了部分特征,它更倾向于“组合优于继承” 的这种思想。将模块分解成相互独立的更小单元,分别处理不同方面的需求,最后以匿名嵌入的方式组合到一起,共同实现对外接口,而且其简短一致的调用方法,更是隐藏了内部实现细节
-
组合 没有父子依赖,不会破坏封装,且整体和局部松耦合,可任意增加来实现扩展,各单元持有单一职责,互无关联,实现和维护更加简单
-
尽管接口也是多态的一种实现方式,但其应该和基于继承体系的多态分离开来
4. expression
-
方法和函数一样,除直接调用外,还可以赋值给变量,或作为参数传递,依照具体引用方式的不同,可分为 expression 和 value 两种状态
Method Expression
-
通过类型引用的 method expression 会被还原为普通函数样式,receiver 是第一参数,调用时须显式传参,至于类型,可以是 T 或 *T,只要目标方法存在于该类型方法集中即可
-
当然也可以以表达式方法调用
Method Expression
-
基于实例或指针引用的 method value,参数签名不会改变,依旧按正常方式调用
-
但当 method value 被赋值给变量或作为参数传递时,会立即计算并赋值该方法执行所须的 receiver 对象,与其绑定,以便在稍后执行时,能隐式传入 receiver 参数
-
编译器会为 method value 生成一个包装函数,实现间接调用,至于 receiver 复制,和闭包的实现方法基本相同,打包成 funcval,经由 DX 寄存器传递
-
当 method value 作为参数时,会复制含 receiver 在内的整个 method value
-
当然如果目标方法的 receiver 时指针类型,那么被复制的仅是指针
-