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

8.1 KiB
Raw Blame History

TSL 变量与常量

文档类型:语法主线 是否可直接用于生成代码:是 是否含可直接照写示例:是 是否含不可照写反例:是 遇到不确定时:先按本页候选页继续判断;03_values_and_literals.md06_expressions_and_operators.md05_functions_and_calls.md16_lexical_structure_and_compile_options.md11_pitfalls.md;仍不命中时回到语法路由中心 index.md;如果问题已经超出语法层,回到 TSL 总入口 ../index.md

这一篇收拢变量与常量初始化规则。

本篇职责

回答“普通变量怎样直接使用、var 在什么位置出现、常量必须怎样初始化、哪些名字一旦绑定就不能再赋值”。

智能体变量/常量判断流程

  1. 普通变量默认直接用 := 首次赋值,不要先补一个没有需求证据的 var 段。
  2. 只有用户要求显式声明或遇到 {$explicit+} 时才优先写 var
  3. 常量声明必须同时初始化;默认只生成 const name = value;,顶层脚本常量需要后续脚本语句时,仍按 .tsl 语句区规则组织。
  4. 多参数赋值按 [a, b] := array(...) 写;单变量拆包必须写成 [name, ] := array(...)
  5. 如果问题已经变成表达式求值、函数参数、运行时类型 / 转换、或 {$explicit+} 之外的编译选项,不要留在变量页硬推断;分别跳到 06_expressions_and_operators.md05_functions_and_calls.md17_types_and_conversions.md16_lexical_structure_and_compile_options.md
  6. 没有对应代码块时不要发明变量/常量写法;尤其不要从 Pascal 的声明习惯反推 TSL 必须先声明变量。

核心规则

  • 默认变量模型是“直接赋值即得到变量”,不要求先写 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;

普通变量与显式声明

默认变量模型:

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

a := 1;
b := array(1, 2, 3);
writeLn(a);
writeLn(b[1]);

代码块身份:输出片段

1
2

显式 var 写法:

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

var a;
a := 1;

{$explicit+} 下的显式声明:

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

{$explicit+}
var a;
a := 1;
writeLn(a);

代码块身份:输出片段

1

常量初始化

顶层最稳的常量写法:

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

const value = 1;
echo value;

代码块身份:输出片段

1

顶层 const = 也可以写常量表达式:

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

const value = 1 + 2 * 3;
writeLn(value);

代码块身份:输出片段

7

函数内部 const 段:

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

function Demo();
const max_retries = 1 + 2 * 3;
begin
    return max_retries;
end;

unit 接口常量:

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

unit DemoUnit;

interface

const value = 1;
function GetValue();

implementation

function GetValue();
begin
    return value;
end;

end.

类成员常量:

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

type DemoType = class
public
    const value = 1;
end;

顶层 const = 只有在“后面继续接可执行语句”的脚本模型里才成立:

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

const max_retries = 3 + 4;
value := max_retries;

多参数赋值

多参数赋值:

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

[r1, r2] := array(1, 3, 5, 7, 9);
writeLn(r1);
writeLn(r2);

代码块身份:输出片段

1
3

单变量拆包时,末尾逗号不能省略:

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

[re, ] := array(1, 2, 3, 4);
writeLn(re);

代码块身份:输出片段

1

左侧变量比右侧数组更长时,多出的变量为 nil

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

[r1, r2] := array(1);
writeLn(r1);
writeLn(r2 = nil);

代码块身份:输出片段

1
1

右侧元素也可以是数组:

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

[r1, r2] := array((1, 2), (3, 4));
writeLn(r1[0]);
writeLn(r1[1]);
writeLn(r2[0]);
writeLn(r2[1]);

结果说明:

  • 依次输出 1234

代码块身份:输出片段

1
2
3
4

函数返回数组后也可以直接拆包:

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

[error, re] := PairAdd(3, 4);
writeLn(error);
writeLn(re);

function PairAdd(a, b);
begin
    return array(0, a + b);
end;

结果说明:

  • 依次输出 07

代码块身份:输出片段

0
7

函数参数里也可以使用多参数赋值:

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

writeLn(Test(e := 3, [f, g] := array(1, 2), g));

function Test(a, b, c);
begin
    return a + b + c;
end;

结果说明:

  • 输出 6

代码块身份:输出片段

6

默认生成模板

普通变量和顶层常量的默认骨架如下:

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

const max_retries = 3;
counter := max_retries;
items := array(1, 2, 3);

禁止项

  • 以为普通变量必须先写 var 才能使用。
  • 把常量初始化写成普通变量赋值风格。
  • 以为 const = 顶层单独写一行就一定成立。
  • 以为 const 可以只声明名字,不写初始化表达式。
  • 以为单变量拆包可以写成 [a] := array(...)
  • 以为 {$explicit+} 开启后仍然可以继续直接写未声明变量。

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

const value = 1;
value := 2;

上面这类写法会编译失败,报错点在重新赋值这一行。

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

const value = 1;

上面这类“顶层单独一行”的 const = 也会编译失败。

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

const value;

上面这类没有初始化表达式的 const 会编译失败;const 必须写初始化值。

错误原因是常量语句缺少初始化表达式。

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

[re] := array(1, 2, 3);

上面这种单变量拆包写法会报 left side can not be assign to。单变量时必须写成 [re, ] := ...

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

{$explicit+}
a := 1;

上面这类写法会编译失败,主因是 variable not defined

代码块身份:输出片段

variable not defined