# TSL 类型与转换

文档类型：语法深水专题
是否可直接用于生成代码：是
是否含可直接照写示例：是
是否含不可照写反例：是
遇到不确定时：先按本页候选页继续判断；[03_values_and_literals.md](03_values_and_literals.md)、[04_variables_and_constants.md](04_variables_and_constants.md)、[23_fmarray.md](23_fmarray.md)；仍不命中时回到语法路由中心 [index.md](index.md)；如果问题已经超出语法层，回到 TSL 总入口 [../index.md](../index.md)

这一篇吸收语言基础里“数据类型、初始值、弱类型行为、类型转换、复数类型”这一层。

## 本篇职责

回答“当问题不再是怎么声明变量或书写普通字面量，而是运行时值会变成什么类型、默认值是什么、怎样显式转换、复数怎样表示时，应该看哪里”。`var` / `const` 声明选择回看 [04_variables_and_constants.md](04_variables_and_constants.md)，编译期开关回看 [16_lexical_structure_and_compile_options.md](16_lexical_structure_and_compile_options.md)。

## 智能体类型/转换判断流程

1. 先判断要写数值字面量、日期时间、真假值、nil、复数，还是类型转换边界。
2. 整数、实数、日期时间、特殊实数和复数只照本页文档字面量写。
3. 不要把能编译的混合类型表达式误判为能按预期自动转换。
4. 遇到 `var` / `const` 声明选择跳转到 [04_variables_and_constants.md](04_variables_and_constants.md)，遇到 `{$explicit+}` / `{$explicit-}` 等编译选项跳转到 [16_lexical_structure_and_compile_options.md](16_lexical_structure_and_compile_options.md)。
5. 遇到字符串字面量、编码或文本边界跳转到 [03_values_and_literals.md](03_values_and_literals.md)。
6. 没有对应代码块时不要发明类型/转换写法。

## 核心规则

- 整数常量支持十进制、`0x` 十六进制、`0b` 二进制和 `0o` 八进制。
- `100L` 这类后缀写法表示 `Int64` 常量。
- 超过 32 位整数范围的十进制整数字面量 `2147483648` 按 `Int64`，不按实数处理。
- 实数写法包括 `1.5`、`1.0E2`、`1E2`；其中 `1E2` 按实数，不按整数处理。
- 日期时间字面量可写成 `20111231T`、`20101231.0931T`。
- `true` 和 `false` 可以直接使用；打印结果分别是 `1` 和 `0`。
- 条件判断里，`0` 按假值处理，非 `0` 数值按真值处理。
- `inf` 和 `nan` 是特殊实数常量；`ifReal(inf)`、`ifReal(nan)` 都返回 `1`。
- `inf > 1000` 为真，`nan = nan` 为假。
- 未初始化的普通变量会得到整数 `0`。
- 新建对象的普通成员变量默认值是 `nil`。
- 对空数组读取一个尚未赋值的下标时，结果是 `nil`。
- `ifNil(nil)` 可用于显式空值判定。
- 空字符串、空数组和 `nil` 都按假值处理。
- `nil` 可以参与加法；`nil + 1` 和 `1 + nil` 都返回 `1`，`nil + nil` 仍然是 `nil`。
- `ifNumber(...)` 会把整数、`Int64`、实数都视为数值；普通字符串不算数值。
- TSL 不是“完全禁止混合类型表达式”；像 `b + a` 这种“整数 + 字符串”会通过编译，但在运行时会报 `operand type error`。
- 因此，类型转换要显式写出来，例如 `strToInt(...)`，不要把运行时失败留给解释器。
- 复数字面量可以直接写成 `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`。

## 可直接照写示例

### 数值、日期与真值

基础数字字面量与类型判定：

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

```tsl
writeLn(ifInt(100));
writeLn(ifInt(0x10));
writeLn(ifInt(0b10));
writeLn(ifInt(0o10));
writeLn(ifInt64(100L));
writeLn(ifReal(1.5));
writeLn(ifReal(1.0E2));
writeLn(ifInt(1E2));
writeLn(ifReal(1E2));
```

结果说明：

- 前七行都输出 `1`
- `ifInt(1E2)` 输出 `0`
- `ifReal(1E2)` 输出 `1`
- 说明 `100`、`0x10`、`0b10`、`0o10` 都按整数处理
- 说明 `100L` 按 `Int64` 处理
- 说明 `1E2` 按实数，不按整数处理

代码块身份：输出片段

```text
1
0
1
```

超 32 位整数与日期时间字面量：

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

```tsl
writeLn(ifInt64(2147483648));
writeLn(ifReal(2147483648));
d1 := 20111231T;
d2 := 20101231.0931T;
writeLn(dateToStr(d1));
writeLn(dateToStr(d2));
writeLn(timeToStr(d2));
```

结果说明：

- 依次输出 `1`、`0`、`2011-12-31`、`2010-12-31`、`09:31:00`
- 说明 `2147483648` 按 `Int64`，不按实数处理
- 说明 `20111231T`、`20101231.0931T` 这类日期时间字面量可以直接使用

布尔常量、数值真值和特殊实数：

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

```tsl
writeLn(true);
writeLn(false);
if 2 then writeLn(1) else writeLn(0);
if 0 then writeLn(1) else writeLn(0);
if -1 then writeLn(1) else writeLn(0);
writeLn(ifReal(inf));
writeLn(ifReal(nan));
writeLn(inf > 1000);
writeLn(nan = nan);
```

结果说明：

- 前两行分别输出 `1`、`0`
- `if 2` 输出 `1`，`if 0` 输出 `0`，`if -1` 输出 `1`
- `ifReal(inf)` 和 `ifReal(nan)` 都输出 `1`
- `inf > 1000` 输出 `1`
- `nan = nan` 输出 `0`
- 说明 `true` / `false` / `inf` / `nan` 属于文档明确常量
- 说明数值条件判断里，`0` 为假，非 `0` 为真

### 初始值与空值

变量初始值与缺失值：

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

```tsl
writeLn(a);
holder := new Holder();
writeLn(holder.Value = nil);
arr := array();
writeLn(arr[0] = nil);

type Holder = class
public
    Value;
end;
```

结果说明：

- 依次输出 `0`、`1`、`1`
- 说明未初始化普通变量默认是整数 `0`
- 说明类成员默认值是 `nil`（`holder.Value`）
- 也说明空数组读取尚未赋值的下标时，结果是 `nil`

`nil` 的显式判定与加法边界：

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

```tsl
writeLn(ifNil(nil));
writeLn(nil + 1);
writeLn(1 + nil);
writeLn(nil + nil = nil);
```

结果说明：

- 依次输出 `1`、`1`、`1`、`1`
- 说明 `ifNil(nil)` 是可用的显式空值判定
- 说明 `nil` 可以直接参与加法
- 其中 `nil + 1` 和 `1 + nil` 都得到 `1`
- `nil + nil` 仍保持为 `nil`

空值条件判断：

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

```tsl
if "" then writeLn(0) else writeLn(1);
if array() then writeLn(0) else writeLn(1);
if nil then writeLn(0) else writeLn(1);
```

结果说明：

- 依次输出 `1`、`1`、`1`
- 说明空字符串、空数组和 `nil` 都按假值处理

`ifNumber(...)` 的最小边界：

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

```tsl
writeLn(ifNumber(100));
writeLn(ifNumber(100L));
writeLn(ifNumber(1.5));
writeLn(ifNumber("100"));
```

结果说明：

- 依次输出 `1`、`1`、`1`、`0`
- 说明 `ifNumber(...)` 接受整数、`Int64`、实数
- 也说明普通数字字符串不会被 `ifNumber(...)` 直接当成数值

### 显式类型转换

显式类型转换的正向例子：

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

```tsl
a := "1234";
b := 1;
c := b + strToInt(a);
writeLn(c);
```

结果说明：

- 输出 `1235`
- 说明显式转换后，字符串数值与整数可以按预期参与加法

### 复数

复数常量、类型与基础读取：

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

```tsl
z1 := 4 + 3j;
z2 := complex(5, -2);
writeLn(dataType(z1));
writeLn(ifComplex(z1));
writeLn(real(z1));
writeLn(imag(z1));
writeLn(z2);
```

结果说明：

- `dataType(4 + 3j)` 返回 `41`
- `ifComplex(4 + 3j)` 返回 `1`
- `real(4 + 3j)` 返回 `4`
- `imag(4 + 3j)` 返回 `3`
- `complex(5, -2)` 打印结果是 `5-2j`

代码块身份：输出片段

```text
41
1
4
3
```

共轭、模与等值比较：

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

```tsl
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);
```

结果说明：

- `abs(4 + 3j)` 返回 `5`
- `conj(4 + 3j)` 的实部是 `4`、虚部是 `-3`
- `3.15 = 3.15 + 0j` 比较结果为真

复数 `Array` 与复数 `FMArray`：

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

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

结果说明：

- `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
z1 := 4 + 3j;
z2 := 5 + 12j;
writeLn(z1 + z2);
writeLn(z2 - z1);
writeLn(z1 * z2);
writeLn(z2 / z1);
```

结果说明：

- `z1 + z2` 得 `9.0+15.0j`
- `z2 - z1` 得 `1.0+9.0j`
- `z1 * z2` 得 `-16.0+63.0j`
- `z2 / z1` 得 `2.24+1.32j`
- 复数参与运算后实部虚部按浮点显示（带 `.0`）
- 复数在四则运算上和实数写法一致，也支持与实数混合运算

复数矩阵乘 `:*`：

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

```tsl
a := array((-1 + 1j), (-3 + 1j));
b := array((2 + 2j, 1 + 3j));
writeLn(tostn(a :* b));
```

结果说明：

- 复数矩阵同样用 `:*` 做矩阵乘（区别于逐单元乘 `*`），矩阵乘除乘方算符体系见 [22_matrix_deep_dive.md](22_matrix_deep_dive.md)
- `a` 是 `2 x 1`、`b` 是 `1 x 2`，`a :* b` 得 `2 x 2` 结果矩阵
- 结果是 `array((-4.0+0.0j,-4.0-2.0j),(-8.0-4.0j,-6.0-8.0j))`

> 版本边界：复数相关功能只在新一代客户端与新一代服务器支持；本节示例在支持复数的运行环境（如新一代服务端）验证。虚数单位固定用 `j`，不是 `i`。

复数最短骨架：

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

```tsl
z := 4 + 3j;
writeLn(real(z));
writeLn(imag(z));
```

## 禁止项

- 不要把“能编译”误解成“会自动按期望类型转换”。
- 不要把数字字符串直接当成数值参与算术；需要数值语义时先显式转换。
- 不要从其他语言的 truthy/falsy 或隐式转换规则反推 TSL。
- 不要把复数统计函数、分解函数与更大函数族当成本页文档能力。

代码块身份：反例 / 不可照写

```text
a := "1234";
b := 1;
writeLn(b + a);
```

上面这种写法不作为可写事实。它可能通过编译，但运行时会报 `Addition instruction error, operand type error`；不要把“能编译”误解成“会自动按你期望的类型转换”。
