playbook/docs/tsl/syntax/24_object_overloads_and_ite...

8.5 KiB
Raw Blame History

TSL 对象重载与迭代

文档类型:语法深水专题 是否可直接用于生成代码:仅部分 是否含可直接照写示例:是 是否含不可照写反例:否 遇到不确定时:先按本页候选页继续判断;08_objects_and_classes.md20_object_runtime_and_introspection.md17_types_and_conversions.md;仍不命中时回到语法路由中心 index.md;如果问题已经超出语法层,回到 TSL 总入口 ../index.md

这一篇只讲对象直接参与语言级操作的文档能力:基础算符重载、[] 重载、for in 重载,以及 mrows / mcols / msize 这类矩阵关键字重载。

本篇职责

回答“当类不只是普通对象,而要直接参与 obj + xobj[index]for v in objmrows(obj) 这类语言级操作时,支持哪些文档明确写法”。

智能体对象重载/迭代判断流程

  1. 先判断要重载二元算符、下标、for in,还是矩阵尺寸函数。
  2. 对象重载只照本页明确的 operator 签名写,不要从未写入文档资料扩展未知重载。
  3. 普通对象模型先回看 08_objects_and_classes.md,不要在重载页发明类基础语法。
  4. 未列入本页主干的重载族不要写成语法事实。
  5. 没有对应代码块时不要发明对象重载/迭代写法。

核心规则

  • 对象二元算符重载的最小可靠形态是成员方法 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 / :: / :. 重载,直接当成语法事实。

可直接照写示例

二元算符重载

代码块身份:可直接照写示例

t1 := new TComplex();
t1.vReal := 10;
t1.vImaginary := 100;
t2 := t1 + 10;
writeLn(t2.vReal);
writeLn(t1 < 5);
writeLn(t1 < 300);
writeLn(5 < t1);

type TComplex = class
public
    vReal;
    vImaginary;
    function operator + (data);
    begin
        r := new TComplex();
        if ifNumber(data) then
        begin
            r.vReal := vReal + data;
        end
        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
        begin
            v := vReal < data;
        end
        else
        begin
            v := (vReal ^ 2 + vImaginary ^ 2) < data.vReal ^ 2 + data.vImaginary ^ 2;
        end
        if not isLeft then v := not v;
        return v;
    end;
end;

结果说明:

  • 依次输出 20011
  • 说明 obj + value 可以通过成员 operator + 接管
  • 说明带 isLeft 的比较算符可以同时处理 obj < valuevalue < obj

代码块身份:输出片段

20
0
1
1

[] 重载:operator[] / operator[1]

代码块身份:可直接照写示例

t := array(1, 2, 3, 4, 5);
b := new bb(t);
writeLn(b[2]);
b[3] := 999;
writeLn(b.data[3]);

type bb = class
public
    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;

结果说明:

  • 依次输出 3999
  • 说明 operator[]operator[1] 可以完成单层下标读取和写入

[] 重载:operator[0] / operator[1]

沿用上一段的 bb 类与测试主体,只把读取签名从 function operator[](index); 改成 function operator[0](index, s1);

代码块身份:配置片段 / 概念骨架

type bb = class
public
    // 其余字段、create()、operator[1] 和测试主体同上一段
    function operator[0](index, s1);
    begin
        return data[index];
    end;
end;

结果说明:

  • 依次输出 3999
  • 说明 operator[0] / operator[1] 这组写法在单层下标场景同样可用

for in 重载

代码块身份:可直接照写示例

box := new Box(array("A", "B", "C"));
for v in box do
    writeLn(v);
for i, v in box do
    writeLn(i$":"$v);

type Box = class
public
    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
        begin
            findex := 0;
        end
        else if findex < length(data) - 1 then
        begin
            findex++;
        end
        else
        begin
            return nil;
        end

        if use_pair then
            return array(findex, data[findex]);
        return data[findex];
    end;
end;

结果说明:

  • 单变量循环依次输出 ABC
  • 双变量循环依次输出 0:A1:B2:C
  • 说明 operator for(flag) 可以重载 for in
  • 也说明同一个对象可以按返回值形态同时支持“单变量遍历”和“索引 + 值遍历”

mrows / mcols / msize 重载

代码块身份:可直接照写示例

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]);

type GridWrap = class
public
    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;

结果说明:

  • 依次输出 2323ABC
  • 说明 mrows(obj)mcols(obj)msize(obj) 都可由对象重载接管
  • 说明对象方法式调用 obj.mcols(1) 也可继续取得列下标列表

+++=

代码块身份:可直接照写示例

b := new bb(10);
++b;
writeLn(b.data);
c := b++;
writeLn(c.data);
writeLn(b.data);
b += 5;
writeLn(b.data);

type bb = class
public
    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;

结果说明:

  • 依次输出 11111217
  • 说明前置 ++ 会直接修改对象状态
  • 说明这个最小样例里,后置 b++ 返回的是递增前快照
  • 说明 operator += (v) 可以接管 b += 5

本页不生成的范围

  • :: / :. 遍历重载
  • mcell / mrow / mcol / mIndexCount / mIndex
  • 多级 [] 下标重载
  • 右侧算术如 value + obj
  • 对基础二进制函数的大规模重载族

这些名称只作为边界提示,不作为本页可生成模板。

禁止项

  • 不要从本页 operator 示例外推未写入文档的重载族。
  • 不要把 mcell / mrow / mcol / :: / :. 直接写成可用语法。
  • 不要把多级 [] 下标重载或 value + obj 这类右侧算术写成文档事实。
  • 不要在本页发明普通类语法;基础对象模型回 08_objects_and_classes.md