8.3 KiB
8.3 KiB
Object Overloads And Iteration
文档类型:语法主线 是否可直接用于生成代码:仅部分 是否含已验证可执行示例:是 是否含已验证反例:否 遇到不确定时跳转到:09_objects_and_classes.md、23_object_runtime_and_introspection.md、31_complex_and_weakref.md
手册位置:第 32 篇,共 32 篇。上一篇:31_complex_and_weakref.md。这一篇是当前 syntax 深水专题的最后一篇。
这一篇收拢“对象像数组、像容器、像可遍历值”这一组新一代能力:基础算符重载、[] 重载、for in 重载,以及 mrows / mcols / msize 这类矩阵关键字重载。
这一篇解决什么问题
回答“当类不只是普通对象,而要直接参与 obj + x、obj[index]、for v in obj、mrows(obj) 这类语言级操作时,当前解释器到底支持哪些真实写法”。
必须记住的规则
- 对象二元算符重载当前最小可靠形态是成员方法
function operator + (data);这一类写法。 - 比较算符当前已验证可写成
function operator < (data, isLeft);,用isLeft区分对象在左边还是右边。 - 对象
[]读取当前已验证两种写法:function operator[](index);和function operator[0](index, s1);。 - 对象
[]写入当前已验证写法是function operator[1](index, v);。 function operator for(flag);当前已验证可以重载for in。- 在
operator for(flag)里,flag .& 2可用来区分“一个循环变量”还是“两个循环变量”,flag .& 1可用来区分“第一次进入”还是“继续迭代”。 mrows/mcols/msize当前已验证可以在类里先声明function operator mrows(n);这类签名,再在类外实现function operator ClassName.mrows(n);。- 当前已验证可用的是
mrows(obj)、mcols(obj)、msize(obj)这类关键字调用,以及obj.mcols(1)这类对象方法式调用。 function operator++(v);和function operator += (v);当前也已验证可用。- 不要把历史资料里的裸
function operator;/function operator1;或尚未验证的mcell/mrow/mcol/::/:.重载,直接当成当前解释器事实。
已验证语法
二元算符重载
代码块身份:已验证可执行示例
program test;
type Tcomplex = class
vReal;
vImaginary;
function operator + (data);
begin
r := new Tcomplex();
if ifnumber(data) then
r.vReal := vReal + data
else
begin
r.vReal := vReal + data.vReal;
r.vImaginary := vImaginary + data.vImaginary;
end;
return r;
end;
function operator < (data, isLeft);
begin
if ifnumber(data) then
v := vReal < data
else
v := (vReal ^ 2 + vImaginary ^ 2) < data.vReal ^ 2 + data.vImaginary ^ 2;
if not isLeft then v := not v;
return v;
end;
end;
begin
t1 := new TComplex();
t1.vReal := 10;
t1.vImaginary := 100;
t2 := t1 + 10;
WriteLn(t2.vReal);
WriteLn(t1 < 5);
WriteLn(t1 < 300);
WriteLn(5 < t1);
end.
已验证运行结果:
- 依次输出
20、0、1、1 - 说明
obj + value当前可以通过成员operator +接管 - 说明带
isLeft的比较算符当前可以同时处理obj < value和value < obj
[] 重载:operator[] / operator[1]
代码块身份:已验证可执行示例
program test;
type bb = class
data;
function create(v);
begin
data := v;
end;
function operator[](index);
begin
return data[index];
end;
function operator[1](index, v);
begin
data[index] := v;
end;
end;
begin
t := array(1, 2, 3, 4, 5);
b := new bb(t);
WriteLn(b[2]);
b[3] := 999;
WriteLn(b.data[3]);
end.
已验证运行结果:
- 依次输出
3、999 - 说明当前解释器下,
operator[]和operator[1]可以完成单层下标读取和写入
[] 重载:operator[0] / operator[1]
沿用上一段的 bb 类与测试主体,只把读取签名从 function operator[](index); 改成 function operator[0](index, s1);:
代码块身份:配置片段 / 概念骨架
type bb = class
// 其余字段、Create()、operator[1] 和测试主体同上一段
function operator[0](index, s1);
begin
return data[index];
end;
end;
已验证运行结果:
- 依次输出
3、999 - 说明
operator[0]/operator[1]这组写法在单层下标场景同样可用
for in 重载
代码块身份:已验证可执行示例
program test;
type Box = class
data;
findex;
function create(v);
begin
data := v;
end;
function operator for(flag);
begin
use_pair := flag .& 2;
again := flag .& 1;
if not again then
findex := 0
else if findex < length(data) - 1 then
findex++
else
return nil;
if use_pair then
return array(findex, data[findex]);
return data[findex];
end;
end;
begin
box := new Box(array("A", "B", "C"));
for v in box do
WriteLn(v);
for i, v in box do
WriteLn(i$":"$v);
end.
已验证运行结果:
- 单变量循环依次输出
A、B、C - 双变量循环依次输出
0:A、1:B、2:C - 说明
operator for(flag)当前确实可以重载for in - 也说明同一个对象可以按返回值形态同时支持“单变量遍历”和“索引 + 值遍历”
mrows / mcols / msize 重载
代码块身份:已验证可执行示例
program test;
type GridWrap = class
data;
function create();
begin
data := array(
("A": 1, "B": 2, "C": 3),
("A": 4, "B": 5, "C": 6)
);
end;
function operator mrows(n);
function operator mcols(n);
function operator msize(n);
end;
function operator GridWrap.mrows(n);
begin
_n := ifnil(n) ? 0 : n;
return mrows(data, _n);
end;
function operator GridWrap.mcols(n);
begin
_n := ifnil(n) ? 0 : n;
return mcols(data, _n);
end;
function operator GridWrap.msize(n);
begin
_n := ifnil(n) ? 0 : n;
return msize(data, _n);
end;
begin
g := new GridWrap();
WriteLn(mrows(g));
WriteLn(mcols(g));
sz := msize(g);
WriteLn(sz[0]);
WriteLn(sz[1]);
cols := g.mcols(1);
WriteLn(cols[0]);
WriteLn(cols[1]);
WriteLn(cols[2]);
end.
已验证运行结果:
- 依次输出
2、3、2、3、A、B、C - 说明
mrows(obj)、mcols(obj)、msize(obj)当前都可由对象重载接管 - 说明对象方法式调用
obj.mcols(1)也可继续取得列下标列表
++ 与 +=
代码块身份:已验证可执行示例
program test;
type bb = class
data;
function create(v);
begin
data := v;
end;
function operator++(v);
begin
if v = 0 then
begin
r := new bb();
r.data := data;
r.data++;
return r;
end
else
data++;
end;
function operator += (v);
begin
data += v;
end;
end;
begin
b := new bb(10);
++b;
WriteLn(b.data);
c := b++;
WriteLn(c.data);
WriteLn(b.data);
b += 5;
WriteLn(b.data);
end.
已验证运行结果:
- 依次输出
11、11、12、17 - 说明前置
++会直接修改对象状态 - 说明这个最小样例里,后置
b++返回的是递增前快照 - 说明
operator += (v)当前可以接管b += 5
暂不在本页展开的部分
::/:.遍历重载mcell/mrow/mcol/mIndexCount/mIndex- 多级
[]下标重载 - 右侧算术如
value + obj - 对基础二进制函数的大规模重载族
这些旧资料里都有更深示例,但当前这一篇先只保留已经单独跑通的容器化主干。
跳转指引
- 回看对象模型:见 09_objects_and_classes.md
- 回看语法主入口:见 index.md
- 回看对象运行时反射:见 23_object_runtime_and_introspection.md
- 回看复数与弱引用:见 31_complex_and_weakref.md