Files
playbook/skills/tsl-syntax-reference/references/04_variables_and_constants.md
T
2026-07-29 07:58:05 +00:00

368 lines
6.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TSL 变量与常量
这一篇收拢变量与常量初始化规则。
## 本篇职责
回答“普通变量怎样直接使用、`var` 在什么位置出现、常量必须怎样初始化、哪些名字一旦绑定就不能再赋值”。
## 核心规则
- 默认变量模型是“直接赋值即得到变量”,不要求先写 `var`
- 例如:`a := 1; b := array(1, 2, 3);` 这种写法可直接编译。
- `var name;` 只作为显式声明写法,不能当成默认必需步骤。
- `const name = value;` 是常量初始化的默认生成写法;`const` 不能只声明名字而不初始化。
- 文档规则:
- `const name = value;` 适合顶层脚本常量、函数内部 `const` 段、`unit` 接口常量、类成员常量。
- 顶层脚本里的 `const name = value;` 可以放在后续脚本语句之前;单独只写一行 `const name = value;` 不作为可运行脚本骨架。
- 函数内部 `const = expr`、以及松散脚本顶层的 `const = expr`,都可以把右侧写成常量表达式。
-`const =` 初始化的这些常量不能再次赋值。
- 多参数赋值文档明确写法是 `[a, b] := array(...)`
- 左侧只有一个变量时,末尾逗号不能省略,必须写成 `[a, ] := array(...)`
- 当左侧变量数大于右侧数组长度时,多出的变量会得到 `nil`
- 右侧数组元素也可以是数组;拆出来的变量会直接得到对应子数组。
- 多参数赋值也可以出现在函数调用参数里。
- `{$explicit+}` 开启后,后续变量必须先用 `var` 声明;未声明变量会报 `variable not defined`
## 可直接照写示例
使用这些示例时遵守:
- 默认生成普通变量时直接用 `:=`;只有用户明确要求或 `{$explicit+}` 场景才复制 `var`
- 普通示例默认按 `.tsl` 脚本语句区书写;需要函数或类型时,放在后置声明区。
- 复制常量示例时只使用 `const name = value;`
### 普通变量与显式声明
<!-- tags: 怎么声明变量, 变量要不要先定义, 直接赋值, var 用不用写 -->
默认变量模型:
代码块身份:可直接照写示例
```tsl
a := 1;
b := array(1, 2, 3);
writeLn(a);
writeLn(b[1]);
```
代码块身份:输出片段
```text
1
2
```
显式 `var` 写法:
代码块身份:可直接照写示例
```tsl
var a;
a := 1;
```
`{$explicit+}` 下的显式声明:
代码块身份:可直接照写示例
```tsl
{$explicit+}
var a;
a := 1;
writeLn(a);
```
代码块身份:输出片段
```text
1
```
### 常量初始化
<!-- tags: 定义常量, 只读的值, 不能改的值, const 怎么写 -->
顶层最稳的常量写法:
代码块身份:可直接照写示例
```tsl
const kValue = 1;
echo kValue;
```
代码块身份:输出片段
```text
1
```
顶层 `const =` 也可以写常量表达式:
代码块身份:可直接照写示例
```tsl
const kValue = 1 + 2 * 3;
writeLn(kValue);
```
代码块身份:输出片段
```text
7
```
函数内部 `const` 段:
代码块身份:可直接照写示例
```tsl
function Demo();
const max_retries = 1 + 2 * 3;
begin
return max_retries;
end;
```
`unit` 接口常量:
代码块身份:可直接照写示例
```tsl
unit DemoUnit;
interface
const kValue = 1;
function GetValue();
implementation
function GetValue();
begin
return kValue;
end;
end.
```
类成员常量:
代码块身份:可直接照写示例
```tsl
type DemoType = class
public
const kValue = 1;
end;
```
顶层 `const =` 只有在“后面继续接可执行语句”的脚本模型里才成立:
代码块身份:可直接照写示例
```tsl
const kMaxRetries = 3 + 4;
value := kMaxRetries;
```
### 多参数赋值
<!-- tags: 一次赋多个变量, 解构赋值, 拆数组到变量, 同时取两个值 -->
多参数赋值:
代码块身份:可直接照写示例
```tsl
[r1, r2] := array(1, 3, 5, 7, 9);
writeLn(r1);
writeLn(r2);
```
代码块身份:输出片段
```text
1
3
```
单变量拆包时,末尾逗号不能省略:
代码块身份:可直接照写示例
```tsl
[re, ] := array(1, 2, 3, 4);
writeLn(re);
```
代码块身份:输出片段
```text
1
```
左侧变量比右侧数组更长时,多出的变量为 `nil`
代码块身份:可直接照写示例
```tsl
[r1, r2] := array(1);
writeLn(r1);
writeLn(r2 = nil);
```
代码块身份:输出片段
```text
1
1
```
右侧元素也可以是数组:
代码块身份:可直接照写示例
```tsl
[r1, r2] := array((1, 2), (3, 4));
writeLn(r1[0]);
writeLn(r1[1]);
writeLn(r2[0]);
writeLn(r2[1]);
```
结果说明:
- 依次输出 `1``2``3``4`
代码块身份:输出片段
```text
1
2
3
4
```
函数返回数组后也可以直接拆包:
代码块身份:可直接照写示例
```tsl
[error, re] := PairAdd(3, 4);
writeLn(error);
writeLn(re);
function PairAdd(a, b);
begin
return array(0, a + b);
end;
```
结果说明:
- 依次输出 `0``7`
代码块身份:输出片段
```text
0
7
```
函数参数里也可以使用多参数赋值:
代码块身份:可直接照写示例
```tsl
writeLn(Test(e := 3, [f, g] := array(1, 2), g));
function Test(a, b, c);
begin
return a + b + c;
end;
```
结果说明:
- 输出 `6`
代码块身份:输出片段
```text
6
```
## 默认生成模板
普通变量和顶层常量的默认骨架如下:
代码块身份:可直接照写示例
```tsl
const kMaxRetries = 3;
counter := kMaxRetries;
items := array(1, 2, 3);
```
## 禁止项
- 以为普通变量必须先写 `var` 才能使用。
- 把常量初始化写成普通变量赋值风格。
- 以为 `const =` 顶层单独写一行就一定成立。
- 以为 `const` 可以只声明名字,不写初始化表达式。
- 以为单变量拆包可以写成 `[a] := array(...)`
- 以为 `{$explicit+}` 开启后仍然可以继续直接写未声明变量。
代码块身份:反例 / 不可照写
```text
const value = 1;
value := 2;
```
上面这类写法会编译失败,报错点在重新赋值这一行。
代码块身份:反例 / 不可照写
```text
const value = 1;
```
上面这类“顶层单独一行”的 `const =` 也会编译失败。
代码块身份:反例 / 不可照写
```text
const value;
```
上面这类没有初始化表达式的 `const` 会编译失败;`const` 必须写初始化值。
错误原因是常量语句缺少初始化表达式。
代码块身份:反例 / 不可照写
```text
[re] := array(1, 2, 3);
```
上面这种单变量拆包写法会报 `left side can not be assign to`。单变量时必须写成 `[re, ] := ...`
代码块身份:反例 / 不可照写
```text
{$explicit+}
a := 1;
```
上面这类写法会编译失败,主因是 `variable not defined`
代码块身份:输出片段
```text
variable not defined
```