# Object Overloads And Iteration 文档类型:语法主线 是否可直接用于生成代码:仅部分 是否含已验证可执行示例:是 是否含已验证反例:否 遇到不确定时跳转到:[09_objects_and_classes.md](09_objects_and_classes.md)、[23_object_runtime_and_introspection.md](23_object_runtime_and_introspection.md)、[31_complex_and_weakref.md](31_complex_and_weakref.md) 手册位置:第 32 篇,共 32 篇。上一篇:[31_complex_and_weakref.md](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` / `::` / `:.` 重载,直接当成当前解释器事实。 ## 已验证语法 ### 二元算符重载 代码块身份:已验证可执行示例 ```tsl 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]` 代码块身份:已验证可执行示例 ```tsl 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);`: 代码块身份:配置片段 / 概念骨架 ```tsl 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` 重载 代码块身份:已验证可执行示例 ```tsl 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` 重载 代码块身份:已验证可执行示例 ```tsl 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)` 也可继续取得列下标列表 ### `++` 与 `+=` 代码块身份:已验证可执行示例 ```tsl 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](09_objects_and_classes.md) - 回看语法主入口:见 [index.md](index.md) - 回看对象运行时反射:见 [23_object_runtime_and_introspection.md](23_object_runtime_and_introspection.md) - 回看复数与弱引用:见 [31_complex_and_weakref.md](31_complex_and_weakref.md)