# Complex And WeakRef 文档类型:语法主线 是否可直接用于生成代码:仅部分 是否含已验证可执行示例:是 是否含已验证反例:是 遇到不确定时跳转到:[09_objects_and_classes.md](09_objects_and_classes.md)、[32_object_overloads_and_iteration.md](32_object_overloads_and_iteration.md)、[12_pitfalls.md](12_pitfalls.md) 手册位置:第 31 篇,共 32 篇。上一篇:[30_runtime_services_and_global_cache.md](30_runtime_services_and_global_cache.md)。下一篇:[32_object_overloads_and_iteration.md](32_object_overloads_and_iteration.md)。 这一篇只讲当前解释器下已经实际跑通的两组新一代语言能力:复数,以及弱引用 / 自动弱引用里当前真正可靠的最小写法。 ## 这一篇解决什么问题 回答“复数现在到底怎样写,弱引用到底有哪些语法真的能用,哪些历史资料里的写法今天不能直接照抄”。 ## 必须记住的规则 - 复数字面量可以直接写成 `a + bj`,也可以用 `complex(a, b)` 构造。 - `datatype(z)` 对复数返回 `41`,`ifcomplex(z)` 对复数返回 `1`。 - `real`、`imag`、`conj`、`abs` 当前都已验证可用。 - 当前解释器里,实数 `x` 与复数 `x + 0j` 的相等比较结果为真。 - `complex(array(...), imag)` 会返回 `Array`;`complex(fmarray..., imag)` 会返回 `FMArray`,并且其单元格类型是 `41`。 - 弱引用能力的条件编译宏当前已验证是 `weakptr`;自动弱引用相关宏是 `AutoWeak`。 - `weakref(obj)` 可以创建弱引用;对象仍存活时,`weakref_get(w)` 可以拿回强引用。 - `checkweakref(w)` 当前已验证:对象仍存活时返回 `1`,对象已释放后返回 `-1`。 - 对已经失效的弱引用直接调用 `weakref_get(w)`,当前解释器里会运行报错,不要把它当成“安全返回 nil”的接口。 - 类成员上的 `[WeakRef] field;` 和 `[AutoRef] field;` 当前已验证可以通过。 - `[WeakRef]` 成员不会阻止对象析构;强引用释放后,对象会正常销毁。 - 历史资料里的类内段落式 `WeakRef;` / `AutoRef;` 在当前解释器里没有通过,错误信息包含 `invalid class definition`。 ## 已验证语法 ### 复数常量、类型与基础读取 代码块身份:已验证可执行示例 ```tsl program test; begin z1 := 4 + 3j; z2 := complex(5, -2); WriteLn(datatype(z1)); WriteLn(ifcomplex(z1)); WriteLn(real(z1)); WriteLn(imag(z1)); WriteLn(z2); end. ``` 已验证运行结果: - `datatype(4 + 3j)` 返回 `41` - `ifcomplex(4 + 3j)` 返回 `1` - `real(4 + 3j)` 返回 `4` - `imag(4 + 3j)` 返回 `3` - `complex(5, -2)` 打印结果是 `5-2j` ### 共轭、模与等值比较 代码块身份:已验证可执行示例 ```tsl program test; begin z := 4 + 3j; c := conj(z); WriteLn(abs(z)); WriteLn(real(c)); WriteLn(imag(c)); if 3.15 = 3.15 + 0j then WriteLn(1); else WriteLn(0); end. ``` 已验证运行结果: - `abs(4 + 3j)` 返回 `5` - `conj(4 + 3j)` 的实部是 `4`、虚部是 `-3` - `3.15 = 3.15 + 0j` 当前比较结果为真 ### 复数 `Array` 与复数 `FMArray` 代码块身份:已验证可执行示例 ```tsl program test; begin a := complex(array(1, 2, 3), 5.5); f := complex(fmarray[1, 2, 3], 5.5); WriteLn(datatype(a)); WriteLn(length(a)); WriteLn(a[0], ',', a[1], ',', a[2]); WriteLn(datatype(f)); WriteLn(datatype(f, 1)); WriteLn(length(f)); WriteLn(f[0], ',', f[1], ',', f[2]); end. ``` 已验证运行结果: - `complex(array(1, 2, 3), 5.5)` 的 `datatype` 是 `5` - 上述复数数组长度是 `3`,三个元素依次是 `1+5.5j`、`2+5.5j`、`3+5.5j` - `complex(fmarray[1, 2, 3], 5.5)` 的 `datatype` 是 `27` - 上述复数 `FMArray` 的单元格类型 `datatype(f, 1)` 是 `41` - 该 `FMArray` 长度是 `3`,三个元素依次是 `1+5.5j`、`2+5.5j`、`3+5.5j` ### 弱引用能力的条件编译判定 代码块身份:已验证可执行示例 ```tsl program test; begin {$IFDEF weakptr} WriteLn('weakptr'); {$ELSE} WriteLn('Noweakptr'); {$ENDIF} {$IFDEF AutoWeak} WriteLn('AutoWeak'); {$ELSE} WriteLn('NoAutoWeak'); {$ENDIF} end. ``` 已验证运行结果: - 当前解释器会输出 `weakptr` - 当前解释器也会输出 `AutoWeak` - 说明这代解释器里,弱引用能力的条件编译开关应写成 `weakptr`,自动弱引用能力的开关应写成 `AutoWeak` ### `weakref`、`weakref_get` 与 `checkweakref` 对象仍然存活时: 代码块身份:已验证可执行示例 ```tsl program test; type TNode = class name; function create(v); begin name := v; end; end; begin a := new TNode('A'); w := weakref(a); WriteLn(checkweakref(w)); s := weakref_get(w); WriteLn(s.name); end. ``` 已验证运行结果: - `checkweakref(w)` 返回 `1` - `weakref_get(w)` 能拿回强引用 - 通过拿回的强引用可继续访问对象成员,此处输出 `A` 沿用同一个 `TNode`,只把主体改成下面这样: 代码块身份:配置片段 / 概念骨架 ```tsl program test; begin a := new TNode('A'); w := weakref(a); WriteLn(checkweakref(w)); a := nil; WriteLn(checkweakref(w)); end. ``` 已验证运行结果: - 创建后 `checkweakref(w)` 返回 `1` - 把最后一个强引用设为 `nil` 后,`checkweakref(w)` 返回 `-1` 当前还额外验证到: 代码块身份:反例 / 不可照写 ```text a := new TNode('A'); w := weakref(a); a := nil; t := weakref_get(w); ``` 上面这种写法在当前解释器里会运行报错,因此访问弱引用前应先做 `checkweakref(w)` 判定。 ### `[WeakRef]` 与 `[AutoRef]` 成员标记 成员级标记当前可以直接写在类里: 代码块身份:已验证可执行示例 ```tsl program test; type TChild = class public [WeakRef] owner1; [AutoRef] owner2; end; begin WriteLn(1); end. ``` 已验证运行结果: - 上述写法可以正常执行,并输出 `1` - 说明 `[WeakRef] field;` 和 `[AutoRef] field;` 当前都能通过 `[WeakRef]` 成员不会阻止对象析构: 代码块身份:已验证可执行示例 ```tsl program test; type TA = class public function destroy(); begin WriteLn('Destroy'); end; end; type TB = class public [WeakRef] owner; function Bind(v); begin owner := v; end; end; begin a := new TA(); b := new TB(); b.Bind(a); a := nil; WriteLn('AfterNil'); end. ``` 已验证运行结果: - 输出顺序是 `Destroy`、`AfterNil` - 说明 `TB.owner` 作为 `[WeakRef]` 成员,不会把 `TA` 实例继续强持有 ## 暂不在本页展开的部分 - 复数统计函数、分解函数与更大函数族 - `MakeWeakRef`、`MakeStrongRef`、`weakref_check` 等别名接口 - `property write` 传播自动弱引用的更复杂规则 - 循环引用场景里的完整模式化写法 ## 最小可编译示例 复数最短骨架: 代码块身份:已验证可执行示例 ```tsl program test; begin z := 4 + 3j; WriteLn(real(z)); WriteLn(imag(z)); end. ``` 弱引用最短骨架: 代码块身份:已验证可执行示例 ```tsl program test; type TNode = class name; function create(v); begin name := v; end; end; begin a := new TNode('A'); w := weakref(a); WriteLn(checkweakref(w)); end. ``` ## 常见误写 - 把弱引用能力的条件编译宏写成 `WeakRef`。 - 以为 `weakref_get(deadWeakRef)` 会像普通可空访问那样安全返回 `nil`。 - 以为历史资料里的类内段落式 `WeakRef;` / `AutoRef;` 现在也能直接通过。 - 以为 `[WeakRef]` 成员会继续强持有对象。 代码块身份:反例 / 不可照写 ```text type TChild = class public owner0; [WeakRef] owner1; WeakRef; owner2; AutoRef; owner3; end; ``` 上面这种把 `WeakRef;` / `AutoRef;` 当作类内段落切换的写法,在当前解释器里会编译失败,错误信息包含 `invalid class definition`。 ## 跳转指引 - 回看语法主入口:见 [index.md](index.md) - 回看对象主线:见 [09_objects_and_classes.md](09_objects_and_classes.md) - 看对象重载:见 [32_object_overloads_and_iteration.md](32_object_overloads_and_iteration.md)