playbook/docs/tsl/syntax/05_variables_and_constants.md

302 lines
6.6 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.

# Variables And Constants
文档类型:语法主线
是否可直接用于生成代码:是
是否含已验证可执行示例:是
是否含已验证反例:是
遇到不确定时跳转到:[04_values_and_literals.md](04_values_and_literals.md)、[06_functions_and_calls.md](06_functions_and_calls.md)、[12_pitfalls.md](12_pitfalls.md)
手册位置:第 5 篇,共 32 篇。上一篇:[04_values_and_literals.md](04_values_and_literals.md)。下一篇:[06_functions_and_calls.md](06_functions_and_calls.md)。
这一篇收拢变量、常量与两种常量写法。
## 这一篇解决什么问题
回答“普通变量怎样直接使用、`var` 在什么位置出现、常量有哪些基本写法、哪些名字一旦绑定就不能再赋值”。
## 必须记住的规则
- 默认变量模型是“直接赋值即得到变量”,不要求先写 `var`
- 例如:`a := 1; b := array(1, 2, 3);` 这种写法已验证可直接编译。
- `var name;` 目前只能当成一种显式声明写法,不能当成默认必需步骤。
- `const Name = value;``const name := value;` 不能当成完全等价的两种写法。
- 已验证:
- `const Name = value;` 适合函数内部 `const` 段、`unit` 接口常量、类成员常量。
- `const name := value;` 适合顶层直接写的常量,单独成段也能编译。
- 当前已验证:函数内部 `const = expr`、以及松散脚本顶层的 `const = expr` / `const := expr`,都可以把右侧写成常量表达式。
- 这两种常量在当前解释器里都不能再次赋值。
- 当前解释器接受多参数赋值:`[a, b] := array(...)`。
- 左侧只有一个变量时,末尾逗号不能省略,必须写成 `[a, ] := array(...)`
- 当左侧变量数大于右侧数组长度时,多出的变量会得到 `nil`
- 右侧数组元素也可以是数组;拆出来的变量会直接得到对应子数组。
- 多参数赋值也可以出现在函数调用参数里。
- 截至 `2026-04-15` 的最小验证里,`{$Explicit+}` 开启后,后续变量必须先用 `var` 声明;未声明变量会报 `variable not defined`
## 已验证语法
默认变量模型:
代码块身份:已验证可执行示例
```tsl
a := 1;
b := array(1, 2, 3);
```
显式 `var` 写法:
代码块身份:已验证可执行示例
```tsl
var a;
a := 1;
```
`{$Explicit+}` 下的显式声明:
代码块身份:已验证可执行示例
```tsl
program test;
begin
{$Explicit+}
var a;
a := 1;
WriteLn(a);
end.
```
顶层最稳的常量写法:
代码块身份:已验证可执行示例
```tsl
const value := 1;
```
顶层 `const :=` 也可以写常量表达式:
代码块身份:已验证可执行示例
```tsl
const value := 1 + 2 * 3;
WriteLn(value);
```
函数内部 `const` 段:
代码块身份:已验证可执行示例
```tsl
function Demo();
const MaxRetries = 1 + 2 * 3;
begin
return MaxRetries;
end;
```
`unit` 接口常量:
代码块身份:已验证可执行示例
```tsl
unit DemoUnit;
interface
const value = 1;
function GetValue();
implementation
function GetValue();
begin
return value;
end;
end.
```
类成员常量:
代码块身份:已验证可执行示例
```tsl
type DemoType = class
const value = 1;
end;
```
顶层 `const =` 只有在“后面继续接可执行语句”的脚本模型里才已验证成立:
代码块身份:已验证可执行示例
```tsl
const MaxRetries = 3 + 4;
value := MaxRetries;
```
代码块身份:已验证可执行示例
```tsl
var a;
a := 1;
```
多参数赋值:
代码块身份:已验证可执行示例
```tsl
[r1, r2] := array(1, 3, 5, 7, 9);
WriteLn(r1);
WriteLn(r2);
```
已验证运行结果:
- 依次输出 `1`、`3`
单变量拆包时,末尾逗号不能省略:
代码块身份:已验证可执行示例
```tsl
[re, ] := array(1, 2, 3, 4);
WriteLn(re);
```
已验证运行结果:
- 输出 `1`
左侧变量比右侧数组更长时,多出的变量为 `nil`
代码块身份:已验证可执行示例
```tsl
[r1, r2] := array(1);
WriteLn(r1);
WriteLn(r2 = nil);
```
已验证运行结果:
- `r1` 输出 `1`
- `r2 = nil` 输出 `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`
函数返回数组后也可以直接拆包:
代码块身份:已验证可执行示例
```tsl
program test;
function PairAdd(a, b);
begin
return array(0, a + b);
end;
begin
[error, re] := PairAdd(3, 4);
WriteLn(error);
WriteLn(re);
end.
```
已验证运行结果:
- 依次输出 `0`、`7`
函数参数里也可以使用多参数赋值:
代码块身份:已验证可执行示例
```tsl
program test;
function Test(a, b, c);
begin
return a + b + c;
end;
begin
WriteLn(Test(e := 3, [f, g] := array(1, 2), g));
end.
```
已验证运行结果:
- 输出 `6`
## 最小可编译示例
如果你只是想先落一个可续写的普通变量和顶层常量骨架,用下面这组:
代码块身份:已验证可执行示例
```tsl
const MaxRetries := 3;
counter := MaxRetries;
items := array(1, 2, 3);
```
## 常见误写
- 以为普通变量必须先写 `var` 才能使用。
- 以为 `const =``const :=` 只是初始化方式不同,可以在任何上下文里互换。
- 以为 `const =` 顶层单独写一行就一定成立。
- 以为单变量拆包可以写成 `[a] := array(...)`
- 以为 `{$Explicit+}` 开启后仍然可以继续直接写未声明变量。
代码块身份:反例 / 不可照写
```text
const value := 1;
value := 2;
```
上面这类写法会编译失败,报错点在重新赋值这一行。
代码块身份:反例 / 不可照写
```text
const value = 1;
```
上面这类“顶层单独一行”的 `const =` 在当前解释器里也会编译失败。
代码块身份:反例 / 不可照写
```text
[re] := array(1, 2, 3);
```
上面这种单变量拆包写法在当前解释器里会报 `left side can not be assign to`。单变量时必须写成 `[re, ] := ...`
代码块身份:反例 / 不可照写
```text
program test;
begin
{$Explicit+}
a := 1;
end.
```
上面这类写法在当前解释器里会编译失败,主因是 `variable not defined`
## 跳转指引
- 回看基本类型:见 [04_values_and_literals.md](04_values_and_literals.md)
- 进入表达式:见 [07_expressions_and_operators.md](07_expressions_and_operators.md)
- 看词法和编译选项:见 [18_lexical_structure_and_compile_options.md](18_lexical_structure_and_compile_options.md)
- 看类型与转换:见 [19_types_and_conversions.md](19_types_and_conversions.md)