Files
endorphin-tabularium-docs/content/docs/smalltalk/03-classes-and-methods.md
T

77 lines
2.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 类、方法与元类:行为放在哪里
> 原书依据:第 3 章和第 5 章,印刷页 9–12、21–25,PDF 页 20–23、32–36。
## 状态的可见范围
| 名称 | 用途 | 阅读时应问 |
| --- | --- | --- |
| 实例变量 | 每个实例自己的状态槽位 | 是否继承自父类? |
| 类变量 | 由类及相关子类共享的绑定 | 是否存在跨实例影响? |
| 全局变量 | 经系统字典访问的绑定 | 是否形成隐含依赖? |
| 池变量 | 多个类共享的变量集合 | 类定义引用了哪个池? |
| 参数、临时变量 | 一次方法或块计算的局部名称 | 生命周期与可赋值规则是什么? |
原书第 5 章明确限制对方法参数再赋值。本教程沿用不修改参数的写法,不把其他实现的语法扩展套回原书。
## 用一个小类串起语法
以下为本文编写的历史风格定义。类定义在 Browser 或相应定义工具中提交;后续方法分别安装在实例侧,不是把整段当作 Workspace 表达式执行。
```smalltalk
Object subclass: #StudyCounter
instanceVariableNames: 'count'
classVariableNames: ''
poolDictionaries: ''
category: 'Study-Examples'
```
实例侧方法:
```smalltalk
initialize
count := 0
```
```smalltalk
increment
count := count + 1
```
```smalltalk
value
^count
```
工作区中的使用示意:
```smalltalk
| counter |
counter := StudyCounter new.
counter initialize.
counter increment.
counter value
```
这里显式初始化,不依赖 `new` 是否自动发送 `initialize`。这些安装步骤和类定义消息需要在目标镜像核对。`increment` 没有显式返回,所以返回 `counter`;`value` 返回槽位保存的数值。
## 方法查找
普通消息从接收者的类开始找选择子,找不到就沿父类向上查找。原书的根类为 `Object`。整个链中没有对应方法时,进入 `doesNotUnderstand:` 协议。
重写方法只改变行为的选择,不把接收者换成父类对象。`self` 始终指向当前接收者。
## super 改变查找起点
假设 B 继承 A,C 继承 B;方法 `describe` 定义在 B 中。如果该方法发送 `super name`,查找从 A 开始,即便当前接收者是 C 的实例。若发送 `self name`,查找从接收者实际的类 C 开始。
因此 `super` 不是“父对象”。它保留同一接收者,按方法定义位置确定查找起点。
## 实例侧与类侧
`StudyCounter new` 的接收者是类对象;`counter increment` 的接收者是它的实例。类自身也是对象,类侧方法由元类组织。
读类侧构造方法时,要检查它究竟分配实例、初始化状态还是返回缓存对象。`new` 只是发给类对象的消息,不能把它视为所有类都必须遵循的固定语法。
原书的 primitive 方法把部分操作交给虚拟机。追踪执行路径时,需区分 Smalltalk 方法体与 VM 提供的原语;本教程没有验证任何 VM 的原语源码。