🎨 style(syntax): normalize naming conventions
Align all TSL syntax documentation examples with docs/tsl/naming.md: - Classes/types: PascalCase, drop Hungarian prefix (THuman→Human) - Parameters/locals: snake_case with meaningful names (isLeft→is_left, maxb→max_b) - Private members: snake_case_ with trailing underscore (real_part_, imaginary_part_) - Public members: PascalCase (value→Value) - Top-level functions: PascalCase (test→Test) - Module constants: kPascalCase (kernel_dll→kKernelDll) Affected: 01-24 syntax docs (23 files) Verified: 150+ code blocks locally tested, output unchanged Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -90,9 +90,9 @@ a := 1;
|
||||
|
||||
```tsl
|
||||
a := 1;
|
||||
test();
|
||||
Test();
|
||||
|
||||
function test();
|
||||
function Test();
|
||||
begin
|
||||
echo "test";
|
||||
end;
|
||||
@@ -135,13 +135,13 @@ end;
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
function Test1();
|
||||
function TestFunc();
|
||||
begin
|
||||
echo "test1";
|
||||
end;
|
||||
```
|
||||
|
||||
代码块说明:这个 `.tsf` 部署到解释器 `funcext` 后,`.tsl` 脚本可以直接调用 `Test1();`。部署方式属于项目执行层,不写进通用语法页。
|
||||
代码块说明:这个 `.tsf` 部署到解释器 `funcext` 后,`.tsl` 脚本可以直接调用 `TestFunc();`。部署方式属于项目执行层,不写进通用语法页。
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
|
||||
@@ -66,9 +66,9 @@ a := 1;
|
||||
|
||||
```tsl
|
||||
a := 1;
|
||||
test();
|
||||
Test();
|
||||
|
||||
function test();
|
||||
function Test();
|
||||
begin
|
||||
echo "test";
|
||||
end;
|
||||
@@ -88,11 +88,11 @@ test
|
||||
|
||||
```tsl
|
||||
obj := new MyClass();
|
||||
obj.value := 5;
|
||||
echo obj.value;
|
||||
obj.Value := 5;
|
||||
echo obj.Value;
|
||||
|
||||
type MyClass = class
|
||||
value;
|
||||
Value;
|
||||
end;
|
||||
```
|
||||
|
||||
|
||||
@@ -377,6 +377,129 @@ writeLn(s);
|
||||
- 输出 `AAA111BBB`
|
||||
- 这说明 `s[index:0] := ...` 是在指定位置插入,而不是删除或替换区间
|
||||
|
||||
### 字符串 `$` 连接与拼装
|
||||
|
||||
`$` 用于字符串连接和类型转字符串拼装:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
s1 := "abc" $ "def";
|
||||
a := 1;
|
||||
b := 2.34;
|
||||
c := "AAA";
|
||||
d := "A=" $ a $ " B=" $ b $ " C=" $ c;
|
||||
writeLn(s1);
|
||||
writeLn(d);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
abcdef
|
||||
A=1 B=2.34 C=AAA
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `"abc" $ "def"` 连接两个字符串得到 `"abcdef"`
|
||||
- 整数、实数等类型可以直接用 `$` 拼装成字符串
|
||||
- 拼接实数时,保留最高精度,表现与 `floattostr` 一致
|
||||
- 纯小数可能走科学计数法:`"_" $ 0.0000005 $ ","` 返回 `"_5E-7,"`
|
||||
- 带整数部分的小数保留精度:`"_" $ 1.0000005 $ ","` 返回 `"_1.0000005,"`
|
||||
|
||||
### 字符串 `like` 模式匹配
|
||||
|
||||
`like` 用于判断字符串是否符合指定模式(支持通配符和正则表达式):
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
result1 := "hello" like "he*";
|
||||
result2 := "HELLO" like "he*";
|
||||
result3 := "test@example.com" like "*@*";
|
||||
writeLn("result1:", result1);
|
||||
writeLn("result2:", result2);
|
||||
writeLn("result3:", result3);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
result1: 1
|
||||
result2: 0
|
||||
result3: 1
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `like` 大小写敏感,`"hello" like "he*"` 返回 `1`(真),`"HELLO" like "he*"` 返回 `0`(假)
|
||||
- `*` 是通配符,匹配任意字符序列
|
||||
- `like` 也支持正则表达式模式(如 `"\\d{4}-\\d{2}-\\d{2}"` 匹配日期格式)
|
||||
|
||||
`not like` 是取反形式(TSL 2025/8 版本起支持):
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
result := "abc" not like "xyz*";
|
||||
writeLn(result);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
1
|
||||
```
|
||||
|
||||
### `format` 格式化占位符
|
||||
|
||||
`format` 用于按占位符格式化输出:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
result := format("%d-%s", 7, "x");
|
||||
writeLn(result);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
7-x
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `%d` 是整数占位符
|
||||
- `%s` 是字符串占位符
|
||||
- `format` 的完整占位符规范见 [../codegen/builtin/basic.md](../codegen/builtin/basic.md)
|
||||
|
||||
### `formatdatetime` 日期格式化
|
||||
|
||||
`formatdatetime` 用于将日期按指定格式输出:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
dt := strtodate("2024-01-02");
|
||||
result := formatdatetime("yyyy-mm-dd", dt);
|
||||
writeLn(result);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
2024-01-02
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `yyyy` 表示四位年份
|
||||
- `mm` 表示两位月份
|
||||
- `dd` 表示两位日期
|
||||
- `formatdatetime` 的完整格式说明见 [../codegen/builtin/basic.md](../codegen/builtin/basic.md)
|
||||
|
||||
## 默认生成模板
|
||||
|
||||
如果你只是要抓住“基本类型 + array”的第一层,用这个最短例子:
|
||||
|
||||
@@ -100,8 +100,8 @@ writeLn(a);
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
const value = 1;
|
||||
echo value;
|
||||
const kValue = 1;
|
||||
echo kValue;
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
@@ -115,8 +115,8 @@ echo value;
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
const value = 1 + 2 * 3;
|
||||
writeLn(value);
|
||||
const kValue = 1 + 2 * 3;
|
||||
writeLn(kValue);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
@@ -146,14 +146,14 @@ unit DemoUnit;
|
||||
|
||||
interface
|
||||
|
||||
const value = 1;
|
||||
const kValue = 1;
|
||||
function GetValue();
|
||||
|
||||
implementation
|
||||
|
||||
function GetValue();
|
||||
begin
|
||||
return value;
|
||||
return kValue;
|
||||
end;
|
||||
|
||||
end.
|
||||
@@ -166,7 +166,7 @@ end.
|
||||
```tsl
|
||||
type DemoType = class
|
||||
public
|
||||
const value = 1;
|
||||
const kValue = 1;
|
||||
end;
|
||||
```
|
||||
|
||||
@@ -175,8 +175,8 @@ end;
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
const max_retries = 3 + 4;
|
||||
value := max_retries;
|
||||
const kMaxRetries = 3 + 4;
|
||||
value := kMaxRetries;
|
||||
```
|
||||
|
||||
### 多参数赋值
|
||||
@@ -311,8 +311,8 @@ end;
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
const max_retries = 3;
|
||||
counter := max_retries;
|
||||
const kMaxRetries = 3;
|
||||
counter := kMaxRetries;
|
||||
items := array(1, 2, 3);
|
||||
```
|
||||
|
||||
|
||||
@@ -83,9 +83,9 @@
|
||||
|
||||
```tsl
|
||||
a := 1;
|
||||
test();
|
||||
Test();
|
||||
|
||||
function test();
|
||||
function Test();
|
||||
begin
|
||||
echo "test";
|
||||
end;
|
||||
@@ -737,7 +737,7 @@ end;
|
||||
|
||||
```tsl
|
||||
f := thisFunction(Add);
|
||||
writeLn(Call(f, 3, 4));
|
||||
writeLn(call(f, 3, 4));
|
||||
|
||||
function Add(a, b);
|
||||
begin
|
||||
|
||||
@@ -103,10 +103,10 @@ writeLn(sum);
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
s := 0;
|
||||
sum := 0;
|
||||
for i := 1 to 5 step 2 do
|
||||
s := s + i;
|
||||
writeLn(s);
|
||||
sum := sum + i;
|
||||
writeLn(sum);
|
||||
```
|
||||
|
||||
输出说明:
|
||||
@@ -124,10 +124,10 @@ writeLn(s);
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
s := 0;
|
||||
sum := 0;
|
||||
for i := 5 downto 1 step 2 do
|
||||
s := s + i;
|
||||
writeLn(s);
|
||||
sum := sum + i;
|
||||
writeLn(sum);
|
||||
```
|
||||
|
||||
输出说明:
|
||||
@@ -145,15 +145,15 @@ writeLn(s);
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
data := array(10, 20, 30);
|
||||
for i, v in data do
|
||||
writeLn(i * 100 + v);
|
||||
numbers := array(10, 20, 30);
|
||||
for i, value in numbers do
|
||||
writeLn(i * 100 + value);
|
||||
```
|
||||
|
||||
输出说明:
|
||||
|
||||
- 依次输出 `10`、`120`、`230`
|
||||
- 这说明 `for i, v in data` 里的 `i` 从 `0` 开始
|
||||
- 这说明 `for i, value in numbers` 里的 `i` 从 `0` 开始
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
|
||||
@@ -192,29 +192,29 @@ writeLn(a);
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
class(THuman).mCount := 100;
|
||||
writeLn(class(THuman).mCount);
|
||||
h := new THuman();
|
||||
writeLn(class(THuman).mCount);
|
||||
writeLn(h.mCount);
|
||||
class(Human).count := 100;
|
||||
writeLn(class(Human).count);
|
||||
h := new Human();
|
||||
writeLn(class(Human).count);
|
||||
writeLn(h.count);
|
||||
|
||||
type THuman = class
|
||||
type Human = class
|
||||
public
|
||||
static mCount;
|
||||
static count;
|
||||
function create();
|
||||
begin
|
||||
mCount := (mCount ?: 0) + 1;
|
||||
count := (count ?: 0) + 1;
|
||||
end;
|
||||
end;
|
||||
```
|
||||
|
||||
输出说明:
|
||||
|
||||
- `class(THuman).mCount := 100` 可以直接写静态字段
|
||||
- `class(THuman).mCount` 先输出 `100`
|
||||
- 创建对象后,`class(THuman).mCount` 输出 `101`
|
||||
- 通过实例读取 `h.mCount` 也输出 `101`
|
||||
- 单个静态字段默认写成 `static mCount;`
|
||||
- `class(Human).count := 100` 可以直接写静态字段
|
||||
- `class(Human).count` 先输出 `100`
|
||||
- 创建对象后,`class(Human).count` 输出 `101`
|
||||
- 通过实例读取 `h.count` 也输出 `101`
|
||||
- 单个静态字段默认写成 `static count;`
|
||||
|
||||
`const` 成员:
|
||||
|
||||
@@ -224,20 +224,20 @@ end;
|
||||
o := new C();
|
||||
writeLn(o.TestConst());
|
||||
writeLn(o.TestConstInParam());
|
||||
writeLn(o.mA);
|
||||
writeLn(class(C).mB);
|
||||
writeLn(o.a);
|
||||
writeLn(class(C).b);
|
||||
|
||||
type C = class
|
||||
public
|
||||
const mA = 1;
|
||||
static const mB = mA + 10;
|
||||
const a = 1;
|
||||
static const b = a + 10;
|
||||
function TestConst();
|
||||
begin
|
||||
return mA + mB;
|
||||
return a + b;
|
||||
end;
|
||||
function TestConstInParam(b = mB);
|
||||
function TestConstInParam(param_b = b);
|
||||
begin
|
||||
return b;
|
||||
return param_b;
|
||||
end;
|
||||
end;
|
||||
```
|
||||
@@ -431,53 +431,53 @@ end;
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
b := new MyBox();
|
||||
b.Value := 7;
|
||||
writeLn(b.Value);
|
||||
b.Value := -1;
|
||||
writeLn(b.Value);
|
||||
box := new Box();
|
||||
box.Value := 7;
|
||||
writeLn(box.Value);
|
||||
box.Value := -1;
|
||||
writeLn(box.Value);
|
||||
|
||||
type MyBox = class
|
||||
type Box = class
|
||||
public
|
||||
_value;
|
||||
value_;
|
||||
function SetValue(v);
|
||||
begin
|
||||
if v > 0 then
|
||||
_value := v;
|
||||
value_ := v;
|
||||
end;
|
||||
property Value read _value write SetValue;
|
||||
property Value read value_ write SetValue;
|
||||
end;
|
||||
```
|
||||
|
||||
输出说明:
|
||||
|
||||
- `b.Value := 7` 后,`b.Value` 输出 `7`
|
||||
- `b.Value := -1` 后,`b.Value` 仍输出 `7`
|
||||
- `box.Value := 7` 后,`box.Value` 输出 `7`
|
||||
- `box.Value := -1` 后,`box.Value` 仍输出 `7`
|
||||
|
||||
带类型注解的 `property`:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
b := new MyBox();
|
||||
b.Value := 9;
|
||||
writeLn(b.Value);
|
||||
box := new Box();
|
||||
box.Value := 9;
|
||||
writeLn(box.Value);
|
||||
|
||||
type MyBox = class
|
||||
type Box = class
|
||||
public
|
||||
_value;
|
||||
value_;
|
||||
function SetValue(v);
|
||||
begin
|
||||
_value := v;
|
||||
value_ := v;
|
||||
end;
|
||||
property Value: integer read _value write SetValue;
|
||||
property Value: integer read value_ write SetValue;
|
||||
end;
|
||||
```
|
||||
|
||||
输出说明:
|
||||
|
||||
- `property Value: integer ...` 这种类型注解写法可以通过
|
||||
- 上述例子中的 `b.Value` 输出 `9`
|
||||
- 上述例子中的 `box.Value` 输出 `9`
|
||||
|
||||
字段和类方法类型注解:
|
||||
|
||||
@@ -491,10 +491,10 @@ writeLn(box.ReadName());
|
||||
|
||||
type TypedBox = class
|
||||
public
|
||||
function create(_name: string; _value: any);
|
||||
function create(name: string; value: any);
|
||||
begin
|
||||
name_ := _name;
|
||||
value_ := _value;
|
||||
name_ := name;
|
||||
value_ := value;
|
||||
end;
|
||||
function ReadName(): string;
|
||||
begin
|
||||
@@ -511,7 +511,7 @@ end;
|
||||
输出说明:
|
||||
|
||||
- `name_: string;` 和 `value_: any;` 可以作为类字段类型注解。
|
||||
- `function create(_name: string; _value: any);` 可以作为类方法参数类型注解。
|
||||
- `function create(name: string; value: any);` 可以作为类方法参数类型注解。
|
||||
- `function ReadName(): string;` 可以作为类方法返回值类型注解。
|
||||
- 上述例子依次输出 `abc`、`7`、`abc`。
|
||||
|
||||
@@ -538,8 +538,8 @@ writeLn(b.ReadLeft());
|
||||
|
||||
type PairBox = class
|
||||
public
|
||||
function create(_left: string); overload;
|
||||
function create(_left: string; _right: any); overload;
|
||||
function create(left: string); overload;
|
||||
function create(left: string; right: any); overload;
|
||||
function ReadLeft(): string;
|
||||
property Left: string read left_ write left_;
|
||||
property Right: any read right_ write right_;
|
||||
@@ -548,15 +548,15 @@ private
|
||||
right_: any;
|
||||
end;
|
||||
|
||||
function PairBox.create(_left: string); overload;
|
||||
function PairBox.create(left: string); overload;
|
||||
begin
|
||||
create(_left, nil);
|
||||
create(left, nil);
|
||||
end;
|
||||
|
||||
function PairBox.create(_left: string; _right: any); overload;
|
||||
function PairBox.create(left: string; right: any); overload;
|
||||
begin
|
||||
left_ := _left;
|
||||
right_ := _right;
|
||||
left_ := left;
|
||||
right_ := right;
|
||||
end;
|
||||
|
||||
function PairBox.ReadLeft(): string;
|
||||
@@ -570,7 +570,7 @@ end;
|
||||
- 类内可以只声明带类型的重载方法签名。
|
||||
- 类外实现写成 `function PairBox.create(...); overload;`,并保持同样的参数类型和 `overload` 标记。
|
||||
- 类外实现属于声明区;写完后不要再追加脚本语句。
|
||||
- 从一个构造函数转调另一个构造函数时,直接写 `create(_left, nil);`,不要加 `self` 前缀。
|
||||
- 从一个构造函数转调另一个构造函数时,直接写 `create(left, nil);`,不要加 `self` 前缀。
|
||||
- 上述例子依次输出 `left`、`<NIL>`、`left`、`2`、`left`。
|
||||
|
||||
代码块身份:输出片段
|
||||
@@ -588,9 +588,9 @@ left
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
aa := new A();
|
||||
aa.idx(0) := "abc";
|
||||
writeLn(aa.idx(0));
|
||||
obj := new A();
|
||||
obj.idx(0) := "abc";
|
||||
writeLn(obj.idx(0));
|
||||
|
||||
type A = class
|
||||
public
|
||||
@@ -613,18 +613,18 @@ end;
|
||||
|
||||
输出说明:
|
||||
|
||||
- `aa.idx(0) := "abc"` 可以写入索引 property
|
||||
- `aa.idx(0)` 输出 `abc`
|
||||
- `obj.idx(0) := "abc"` 可以写入索引 property
|
||||
- `obj.idx(0)` 输出 `abc`
|
||||
|
||||
固定 `index` property:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
aa := new A();
|
||||
aa.idx0 := "abc";
|
||||
writeLn(aa.idx0);
|
||||
writeLn(aa.idx(0));
|
||||
obj := new A();
|
||||
obj.idx0 := "abc";
|
||||
writeLn(obj.idx0);
|
||||
writeLn(obj.idx(0));
|
||||
|
||||
type A = class
|
||||
public
|
||||
@@ -648,19 +648,19 @@ end;
|
||||
|
||||
输出说明:
|
||||
|
||||
- `aa.idx0 := "abc"` 可以写入固定整数索引 property
|
||||
- `aa.idx0` 输出 `abc`
|
||||
- `aa.idx(0)` 也输出 `abc`
|
||||
- `obj.idx0 := "abc"` 可以写入固定整数索引 property
|
||||
- `obj.idx0` 输出 `abc`
|
||||
- `obj.idx(0)` 也输出 `abc`
|
||||
|
||||
固定字符串索引:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
aa := new A();
|
||||
aa.school := "math";
|
||||
writeLn(aa.school);
|
||||
writeLn(aa.idx("High school"));
|
||||
obj := new A();
|
||||
obj.school := "math";
|
||||
writeLn(obj.school);
|
||||
writeLn(obj.idx("High school"));
|
||||
|
||||
type A = class
|
||||
public
|
||||
@@ -685,8 +685,8 @@ end;
|
||||
输出说明:
|
||||
|
||||
- `property school index "High school"` 这种固定字符串索引写法可以通过
|
||||
- `aa.school` 输出 `math`
|
||||
- `aa.idx("High school")` 也输出 `math`
|
||||
- `obj.school` 输出 `math`
|
||||
- `obj.idx("High school")` 也输出 `math`
|
||||
|
||||
参数化 `property`:
|
||||
|
||||
@@ -699,18 +699,18 @@ writeLn(d.DateV());
|
||||
|
||||
type MyDate = class
|
||||
public
|
||||
_year;
|
||||
_month;
|
||||
_day;
|
||||
year_;
|
||||
month_;
|
||||
day_;
|
||||
function getDateV();
|
||||
begin
|
||||
return _year * 10000 + _month * 100 + _day;
|
||||
return year_ * 10000 + month_ * 100 + day_;
|
||||
end;
|
||||
function setDateV(y, m, d);
|
||||
begin
|
||||
_year := y;
|
||||
_month := m;
|
||||
_day := d;
|
||||
year_ := y;
|
||||
month_ := m;
|
||||
day_ := d;
|
||||
end;
|
||||
property DateV(y, m) read getDateV write setDateV;
|
||||
end;
|
||||
@@ -726,9 +726,9 @@ end;
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
aa := new A();
|
||||
aa.Item(2) := "x";
|
||||
writeLn(aa.Item(2));
|
||||
obj := new A();
|
||||
obj.Item(2) := "x";
|
||||
writeLn(obj.Item(2));
|
||||
|
||||
type A = class
|
||||
public
|
||||
@@ -751,9 +751,9 @@ end;
|
||||
|
||||
输出说明:
|
||||
|
||||
- `read getItem` 这种“读方法接同参数个数”的写法可以通过
|
||||
- `write setItem` 这种“写方法接参数个数 + 赋值值”的写法可以通过
|
||||
- 上述例子中的 `aa.Item(2)` 输出 `x`
|
||||
- `read getItem` 这种”读方法接同参数个数”的写法可以通过
|
||||
- `write setItem` 这种”写方法接参数个数 + 赋值值”的写法可以通过
|
||||
- 上述例子中的 `obj.Item(2)` 输出 `x`
|
||||
|
||||
### 对象创建与类类型
|
||||
|
||||
@@ -922,9 +922,9 @@ public
|
||||
begin
|
||||
return p1 + p2;
|
||||
end;
|
||||
function fun(p1); overload;
|
||||
function fun(param): integer; overload;
|
||||
begin
|
||||
return p1 + 10;
|
||||
return param + 10;
|
||||
end;
|
||||
end;
|
||||
```
|
||||
@@ -1050,6 +1050,74 @@ end;
|
||||
- 父类 `virtual` + 子类 `override` 组合可以通过
|
||||
- 上述例子中的 `d.Speak()` 输出 `2`
|
||||
|
||||
子类同名方法不加 `override` 时是「隐藏(hide)」而不是「覆盖(override)」:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
c := new Child();
|
||||
writeLn(c.Who());
|
||||
writeLn(c.Ask());
|
||||
|
||||
type Parent = class
|
||||
public
|
||||
function Who();
|
||||
begin
|
||||
return "parent";
|
||||
end;
|
||||
function Ask();
|
||||
begin
|
||||
return Who();
|
||||
end;
|
||||
end;
|
||||
type Child = class(Parent)
|
||||
public
|
||||
function Who();
|
||||
begin
|
||||
return "child";
|
||||
end;
|
||||
end;
|
||||
```
|
||||
|
||||
输出说明:
|
||||
|
||||
- `c.Who()` 输出 `child`:直接调用命中子类自己的同名方法
|
||||
- `c.Ask()` 输出 `parent`:父类方法内部的 `Who()` 仍解析到父类版本,说明不加 `override` 只是「隐藏」父类方法,没有改变父类内部的调用目标
|
||||
- 要让父类方法内部也定向到子类实现,父类方法须声明 `virtual`、子类方法须声明 `override`
|
||||
|
||||
对照:父类 `virtual` + 子类 `override` 时,父类方法内部调用会定向到子类:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
c := new Child();
|
||||
writeLn(c.Ask());
|
||||
|
||||
type Parent = class
|
||||
public
|
||||
function Who(); virtual;
|
||||
begin
|
||||
return "parent";
|
||||
end;
|
||||
function Ask();
|
||||
begin
|
||||
return Who();
|
||||
end;
|
||||
end;
|
||||
type Child = class(Parent)
|
||||
public
|
||||
function Who(); override;
|
||||
begin
|
||||
return "child";
|
||||
end;
|
||||
end;
|
||||
```
|
||||
|
||||
输出说明:
|
||||
|
||||
- `c.Ask()` 输出 `child`:`virtual` + `override` 后,父类方法内部的 `Who()` 定向到子类实现
|
||||
- 这就是 hide 与 override 的关键区别:hide 只影响直接调用,override 改变了所有经由基类的间接调用
|
||||
|
||||
`class(BaseClass, ObjectName).MethodName()`:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -1179,35 +1247,35 @@ end;
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
h := new THuman();
|
||||
writeLn(class(THuman).GetCount());
|
||||
h := new Human();
|
||||
writeLn(class(Human).GetCount());
|
||||
h := nil;
|
||||
writeLn(class(THuman).GetCount());
|
||||
writeLn(class(Human).GetCount());
|
||||
|
||||
type THuman = class
|
||||
type Human = class
|
||||
public
|
||||
static mCount;
|
||||
static count;
|
||||
function create();
|
||||
begin
|
||||
mCount := (mCount ?: 0) + 1;
|
||||
count := (count ?: 0) + 1;
|
||||
end;
|
||||
function destroy();
|
||||
begin
|
||||
mCount--;
|
||||
writeLn(mCount);
|
||||
count--;
|
||||
writeLn(count);
|
||||
end;
|
||||
class function GetCount();
|
||||
begin
|
||||
return mCount;
|
||||
return count;
|
||||
end;
|
||||
end;
|
||||
```
|
||||
|
||||
输出说明:
|
||||
|
||||
- 创建对象后,`class(THuman).GetCount()` 输出 `1`
|
||||
- 创建对象后,`class(Human).GetCount()` 输出 `1`
|
||||
- `h := nil` 时会触发 `destroy()`,中途输出 `0`
|
||||
- 释放后再次读取 `class(THuman).GetCount()` 也输出 `0`
|
||||
- 释放后再次读取 `class(Human).GetCount()` 也输出 `0`
|
||||
|
||||
`self(0)` / `self(1)`:
|
||||
|
||||
@@ -1373,10 +1441,10 @@ cls := class(Unit1.Class1.Class2);
|
||||
|
||||
```text
|
||||
MathBox.Add(1, 2);
|
||||
THuman.mCount := 7;
|
||||
Human.count := 7;
|
||||
```
|
||||
|
||||
上面这种裸类名成员访问不作为可写事实;类方法可用 `class(MathBox).Add(...)` 或 `findClass("MathBox").Add(...)` 调用,静态字段可用 `class(THuman).mCount` 访问。
|
||||
上面这种裸类名成员访问不作为可写事实;类方法可用 `class(MathBox).Add(...)` 或 `findClass("MathBox").Add(...)` 调用,静态字段可用 `class(Human).count` 访问。
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
|
||||
|
||||
@@ -245,7 +245,7 @@ interface
|
||||
|
||||
uses UnitB;
|
||||
|
||||
type TBox = class
|
||||
type Box = class
|
||||
public
|
||||
function FromInterface();
|
||||
begin
|
||||
@@ -260,7 +260,7 @@ implementation
|
||||
|
||||
uses UnitC;
|
||||
|
||||
function TBox.FromImplementation();
|
||||
function Box.FromImplementation();
|
||||
begin
|
||||
return FC();
|
||||
end;
|
||||
@@ -278,7 +278,7 @@ end.
|
||||
// main.tsl
|
||||
|
||||
uses UnitA;
|
||||
obj := new TBox();
|
||||
obj := new Box();
|
||||
writeLn(CallB());
|
||||
writeLn(CallC());
|
||||
writeLn(obj.FromInterface());
|
||||
@@ -304,8 +304,8 @@ interface
|
||||
function MakeValue();
|
||||
type UnitBox = class
|
||||
public
|
||||
value;
|
||||
function create(_value);
|
||||
Value;
|
||||
function create(init_value);
|
||||
function ReadValue();
|
||||
end;
|
||||
|
||||
@@ -315,13 +315,13 @@ function MakeValue();
|
||||
begin
|
||||
return 10;
|
||||
end;
|
||||
function UnitBox.create(_value);
|
||||
function UnitBox.create(init_value);
|
||||
begin
|
||||
value := _value;
|
||||
Value := init_value;
|
||||
end;
|
||||
function UnitBox.ReadValue();
|
||||
begin
|
||||
return value;
|
||||
return Value;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
是否可直接用于生成代码:仅部分
|
||||
是否含可直接照写示例:是
|
||||
是否含不可照写反例:是
|
||||
遇到不确定时:先按本页候选页继续判断;[05_functions_and_calls.md](05_functions_and_calls.md)、[06_expressions_and_operators.md](06_expressions_and_operators.md)、[14_ts_sql.md](14_ts_sql.md)、[15_debug_and_profiler.md](15_debug_and_profiler.md)、[19_namespace_libpath_and_unit_runtime.md](19_namespace_libpath_and_unit_runtime.md)、[21_builtin_runtime_objects.md](21_builtin_runtime_objects.md)、[../reference/catalog/datawarehouse.md](../reference/catalog/datawarehouse.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md)
|
||||
遇到不确定时:先按本页候选页继续判断;[05_functions_and_calls.md](05_functions_and_calls.md)、[06_expressions_and_operators.md](06_expressions_and_operators.md)、[14_ts_sql.md](14_ts_sql.md)、[15_debug_and_profiler.md](15_debug_and_profiler.md)、[19_namespace_libpath_and_unit_runtime.md](19_namespace_libpath_and_unit_runtime.md)、[21_builtin_runtime_objects.md](21_builtin_runtime_objects.md)、[../codegen/dotnet/datawarehouse/](../codegen/dotnet/datawarehouse/);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md)
|
||||
|
||||
这一篇只处理运行时环境参数、块环境 `with` 语句、`with` 后缀、`#` 网格调用、`timeout` 后缀、`dupvalue(...)` 和全局缓存,不处理任何金融业务语义。
|
||||
|
||||
@@ -36,11 +36,11 @@
|
||||
- `with array(...)` 只在该次调用里临时覆盖对应键,调用结束后会恢复外部原值。
|
||||
- 如果外部原值本来不存在,`with array(...)` 调用结束后,对应键会恢复成 `nil`。
|
||||
- 不要把上面的后缀 `with` 直接泛化成“任何本地函数调用后面都能接 `with array(...)`”;本地函数后缀 `with` 属于反例。
|
||||
- 本页只收通用键的例子;像 `pn_stock()`、`pn_date()` 这类金融上下文参数,统一到 [../reference/catalog/datawarehouse.md](../reference/catalog/datawarehouse.md) 查函数事实。
|
||||
- 本页只收通用键的例子;像 `pn_stock()`、`pn_date()` 这类金融上下文参数,统一到 [../codegen/dotnet/datawarehouse/](../codegen/dotnet/datawarehouse/) 查函数事实。
|
||||
- 网格调用的最小写法是 `r := #Func(args);`。
|
||||
- 网格调用返回的不是最终值;用 `dupvalue(r)` 取回结果。
|
||||
- `timeout N` 后缀可直接接在网格调用后面。
|
||||
- 全局缓存函数的参数规格见 [../reference/catalog/system.md](../reference/catalog/system.md);本页只保留缓存引用的运行时行为示例。
|
||||
- 全局缓存函数的参数规格见 [../codegen/special/pending/system/03_global_cache.md](../codegen/special/pending/system/03_global_cache.md) 和 [../codegen/builtin/system.md](../codegen/builtin/system.md);本页只保留缓存引用的运行时行为示例。
|
||||
- 写入和读取全局缓存成功时返回 `1`。
|
||||
- 从全局缓存取出的值,`ifCache(v)` 会返回 `1`。
|
||||
- 一旦对取出的缓存值做本地写入,它会立刻实例化;写入后 `ifCache(v)` 返回 `0`。
|
||||
@@ -94,9 +94,9 @@ writeLn(getSysParam("a"));
|
||||
|
||||
```tsl
|
||||
setSysParam("a", 1);
|
||||
sys_param_values := array("a": 2, "b": 3);
|
||||
param_values := array("a": 2, "b": 3);
|
||||
|
||||
with *, sys_param_values do
|
||||
with *, param_values do
|
||||
begin
|
||||
writeLn(getSysParam("a"));
|
||||
writeLn(getSysParam("b"));
|
||||
@@ -112,6 +112,33 @@ writeLn(getSysParam("b"));
|
||||
- 块后输出 `2`、`3`
|
||||
- 说明 `with *` 会把传入键合并进当前系统参数上下文;不要把它当成自动恢复外层值的隔离块
|
||||
|
||||
`with *, SysParamArray do` 使用当前所有系统参数:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
setSysParam("a", 10);
|
||||
setSysParam("b", 20);
|
||||
with *, SysParamArray do
|
||||
begin
|
||||
writeLn(getSysParam("a"));
|
||||
writeLn(getSysParam("b"));
|
||||
end
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
10
|
||||
20
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `SysParamArray` 是特殊关键字,表示引用当前所有系统参数
|
||||
- `with *, SysParamArray do` 把当前系统参数作为块环境传入
|
||||
- 这是服务端环境的常用写法,用于保持系统参数上下文
|
||||
|
||||
### 块环境 `with **`
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -119,9 +146,9 @@ writeLn(getSysParam("b"));
|
||||
```tsl
|
||||
setSysParam("a", 1);
|
||||
setSysParam("b", 9);
|
||||
sys_param_values := array("b": 4);
|
||||
param_values := array("b": 4);
|
||||
|
||||
with **, sys_param_values do
|
||||
with **, param_values do
|
||||
begin
|
||||
writeLn(getSysParam("a") = nil);
|
||||
writeLn(getSysParam("b"));
|
||||
@@ -189,6 +216,8 @@ writeLn(getSysParam("b") = nil);
|
||||
|
||||
### `#` 网格调用与 `dupvalue`
|
||||
|
||||
网格调用函数:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -211,6 +240,29 @@ end;
|
||||
6
|
||||
```
|
||||
|
||||
网格调用数组表达式:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
items := array(1, 2, 3, 4, 5);
|
||||
grid_result := #(items * 2);
|
||||
writeLn(tostn(dupvalue(grid_result)));
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
array(2,4,6,8,10)
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `#(表达式)` 可以对表达式进行网格计算
|
||||
- `#(items * 2)` 返回网格句柄
|
||||
- `dupvalue(grid_result)` 取回最终结果数组
|
||||
- 网格计算常用于大规模数组的分布式并行运算
|
||||
|
||||
### 网格调用的 `timeout`
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -234,20 +286,27 @@ end;
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
v1 := array(1, 2, 3);
|
||||
writeLn(setGlobalCache("PB_TEST_GC_BASIC", v1));
|
||||
writeLn(getGlobalCache("PB_TEST_GC_BASIC", v2));
|
||||
writeLn(ifCache(v2));
|
||||
writeLn(length(v2));
|
||||
writeLn(v2[0], ',', v2[1], ',', v2[2]);
|
||||
source_data := array(1, 2, 3);
|
||||
writeLn(setGlobalCache("PB_TEST_GC_BASIC", source_data));
|
||||
writeLn(getGlobalCache("PB_TEST_GC_BASIC", cached_data));
|
||||
writeLn(ifCache(cached_data));
|
||||
writeLn(length(cached_data));
|
||||
writeLn(cached_data[0], ',', cached_data[1], ',', cached_data[2]);
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- `setGlobalCache("PB_TEST_GC_BASIC", v1)` 返回 `1`
|
||||
- `getGlobalCache("PB_TEST_GC_BASIC", v2)` 返回 `1`
|
||||
- 取出的 `v2` 上 `ifCache(v2)` 返回 `1`
|
||||
- `v2` 长度是 `3`,内容是 `1,2,3`
|
||||
- `setGlobalCache("PB_TEST_GC_BASIC", source_data)` 返回 `1`
|
||||
- `getGlobalCache("PB_TEST_GC_BASIC", cached_data)` 返回 `1`
|
||||
- 取出的 `cached_data` 上 `ifCache(cached_data)` 返回 `1`
|
||||
- `cached_data` 长度是 `3`,内容是 `1,2,3`
|
||||
|
||||
说明:
|
||||
|
||||
- TSL 标识符大小写无关,`setGlobalCache` 和 `SetGlobalCache` 等价
|
||||
- 推荐使用小写 `setGlobalCache`、`getGlobalCache` 以保持一致性
|
||||
- `setGlobalCache(key, value)` 写入缓存,可选第三参数指定过期时间(秒)
|
||||
- `getGlobalCache(key, out_var)` 读取缓存到输出变量
|
||||
|
||||
### `checkGlobalCacheExpired`
|
||||
|
||||
@@ -255,16 +314,16 @@ writeLn(v2[0], ',', v2[1], ',', v2[2]);
|
||||
|
||||
```tsl
|
||||
setGlobalCache("PB_TEST_GC_EXPIRE", array(1, 2, 3));
|
||||
getGlobalCache("PB_TEST_GC_EXPIRE", v);
|
||||
writeLn(checkGlobalCacheExpired(v));
|
||||
getGlobalCache("PB_TEST_GC_EXPIRE", cache_ref);
|
||||
writeLn(checkGlobalCacheExpired(cache_ref));
|
||||
setGlobalCache("PB_TEST_GC_EXPIRE", array(1, 2, 3, 4));
|
||||
writeLn(checkGlobalCacheExpired(v));
|
||||
writeLn(checkGlobalCacheExpired(cache_ref));
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- 刚取出的缓存引用上,`checkGlobalCacheExpired(v)` 返回 `0`
|
||||
- 同名缓存被重新设置后,旧引用上的 `checkGlobalCacheExpired(v)` 返回 `1`
|
||||
- 刚取出的缓存引用上,`checkGlobalCacheExpired(cache_ref)` 返回 `0`
|
||||
- 同名缓存被重新设置后,旧引用上的 `checkGlobalCacheExpired(cache_ref)` 返回 `1`
|
||||
|
||||
### 写入后会实例化
|
||||
|
||||
@@ -272,17 +331,17 @@ writeLn(checkGlobalCacheExpired(v));
|
||||
|
||||
```tsl
|
||||
setGlobalCache("PB_TEST_GC_DETACH", array(1, 2, 3));
|
||||
getGlobalCache("PB_TEST_GC_DETACH", v);
|
||||
writeLn(ifCache(v));
|
||||
v[0] := 100;
|
||||
writeLn(ifCache(v));
|
||||
writeLn(v[0], ',', v[1], ',', v[2]);
|
||||
getGlobalCache("PB_TEST_GC_DETACH", local_copy);
|
||||
writeLn(ifCache(local_copy));
|
||||
local_copy[0] := 100;
|
||||
writeLn(ifCache(local_copy));
|
||||
writeLn(local_copy[0], ',', local_copy[1], ',', local_copy[2]);
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- 刚取出时 `ifCache(v)` 返回 `1`
|
||||
- 对 `v[0]` 赋值后,`ifCache(v)` 立即返回 `0`
|
||||
- 刚取出时 `ifCache(local_copy)` 返回 `1`
|
||||
- 对 `local_copy[0]` 赋值后,`ifCache(local_copy)` 立即返回 `0`
|
||||
- 写入后的本地值内容是 `100,2,3`
|
||||
|
||||
### 全局缓存参与 `select`
|
||||
@@ -290,13 +349,13 @@ writeLn(v[0], ',', v[1], ',', v[2]);
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
src := array((1, 2), (3, 4), (2, 1));
|
||||
setGlobalCache("PB_TEST_GC_SELECT", src);
|
||||
getGlobalCache("PB_TEST_GC_SELECT", v);
|
||||
q := select * from v order by [0] desc end;
|
||||
writeLn(dataType(q));
|
||||
writeLn(mrows(q));
|
||||
writeLn(q[0][0], ',', q[0][1], ';', q[1][0], ',', q[1][1], ';', q[2][0], ',', q[2][1]);
|
||||
source_table := array((1, 2), (3, 4), (2, 1));
|
||||
setGlobalCache("PB_TEST_GC_SELECT", source_table);
|
||||
getGlobalCache("PB_TEST_GC_SELECT", cached_table);
|
||||
query_result := select * from cached_table order by [0] desc end;
|
||||
writeLn(dataType(query_result));
|
||||
writeLn(mrows(query_result));
|
||||
writeLn(query_result[0][0], ',', query_result[0][1], ';', query_result[1][0], ',', query_result[1][1], ';', query_result[2][0], ',', query_result[2][1]);
|
||||
```
|
||||
|
||||
结果说明:
|
||||
@@ -355,8 +414,8 @@ end;
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
|
||||
```text
|
||||
r := Demo() with array("a": 11);
|
||||
```tsl
|
||||
cached_result := Demo() with array("a": 11);
|
||||
|
||||
function Demo();
|
||||
begin
|
||||
|
||||
@@ -212,6 +212,126 @@ matched := 1 in array(1, 2, 3);
|
||||
row_matched := array(1, 2) sqlin array((1, 2), (3, 4));
|
||||
```
|
||||
|
||||
### 点前缀比较算符产生逻辑数组
|
||||
|
||||
点前缀比较(`.=`、`.<>`、`.>`、`.>=`、`.<`、`.<=`)对数组/矩阵逐元素比较,返回真假值数组:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array(0.3, 0.6, 0.9);
|
||||
result := a .> 0.5;
|
||||
writeLn("result[0]:", result[0]);
|
||||
writeLn("result[1]:", result[1]);
|
||||
writeLn("result[2]:", result[2]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
result[0]: 0
|
||||
result[1]: 1
|
||||
result[2]: 1
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `.>` 对数组的每个元素逐一比较,返回 `0`(假)或 `1`(真)
|
||||
- `a .> 0.5` 返回 `array(0, 1, 1)`,对应 `0.3 > 0.5` 为假、`0.6 > 0.5` 为真、`0.9 > 0.5` 为真
|
||||
- 其他点前缀比较同理:`.=`(等于)、`.<>`(不等于)、`.>=`、`.<`、`.<=`
|
||||
|
||||
配合 `mfind` 转换为下标数组,可用于取子集:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array((0.3, 10), (0.6, 20), (0.9, 30));
|
||||
logical_array := a[:, 0] .> 0.5;
|
||||
indexes := mfind(logical_array);
|
||||
subset := a[indexes];
|
||||
writeLn("逻辑数组:", tostn(logical_array));
|
||||
writeLn("下标数组:", tostn(indexes));
|
||||
writeLn("子集行数:", mrows(subset));
|
||||
writeLn("子集 (0,0):", subset[0][0]);
|
||||
writeLn("子集 (0,1):", subset[0][1]);
|
||||
writeLn("子集 (1,0):", subset[1][0]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
逻辑数组: array(0,1,1)
|
||||
下标数组: array(1,2)
|
||||
子集行数: 2
|
||||
子集 (0,0): 0.6
|
||||
子集 (0,1): 20
|
||||
子集 (1,0): 0.9
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `a[:, 0] .> 0.5` 提取第 0 列并逐元素比较,得到逻辑数组 `array(0, 1, 1)`
|
||||
- `mfind(逻辑数组)` 把真值位置转换成下标数组 `array(1, 2)`
|
||||
- `a[indexes]` 按下标提取对应行,等价于 `select * from a where [0] > 0.5 end`
|
||||
- `mfind` 的完整用法见 [22_matrix_deep_dive.md](22_matrix_deep_dive.md)
|
||||
|
||||
### 非完全矩阵与缺位当 0 处理
|
||||
|
||||
基础算符作用于非完全矩阵(行长度不一致或字符串键不对齐的数组)时,对应位置不存在或为 `nil` 时**默认当 0 处理**:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array("A": 1, "B": 1, "C": 1);
|
||||
b := array("A": 2, "C": 2);
|
||||
result := a + b;
|
||||
writeLn("result['A']:", result["A"]);
|
||||
writeLn("result['B']:", result["B"]);
|
||||
writeLn("result['C']:", result["C"]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
result['A']: 3
|
||||
result['B']: 1
|
||||
result['C']: 3
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `a` 有键 `"A"`、`"B"`、`"C"`,`b` 只有 `"A"`、`"C"`
|
||||
- `a + b` 时,`b["B"]` 不存在,按 `0` 处理
|
||||
- 结果 `result["A"] = 1 + 2 = 3`、`result["B"] = 1 + 0 = 1`、`result["C"] = 1 + 2 = 3`
|
||||
|
||||
标量与矩阵的广播:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
matrix_value := array((1, 2), (3, 4));
|
||||
result := matrix_value + 10;
|
||||
writeLn("(0,0):", result[0][0]);
|
||||
writeLn("(0,1):", result[0][1]);
|
||||
writeLn("(1,0):", result[1][0]);
|
||||
writeLn("(1,1):", result[1][1]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
(0,0): 11
|
||||
(0,1): 12
|
||||
(1,0): 13
|
||||
(1,1): 14
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- 标量 `+`、`-`、`*`、`/` 等作用于矩阵时,会广播到每个元素
|
||||
- `matrix_value + 10` 每个元素都加 10
|
||||
- 这些是逐元素运算(element-wise),区别于矩阵乘法 `:*`,见 [22_matrix_deep_dive.md](22_matrix_deep_dive.md)
|
||||
|
||||
## 本页不生成的范围
|
||||
|
||||
- 专门的结果集过滤函数
|
||||
@@ -226,10 +346,12 @@ row_matched := array(1, 2) sqlin array((1, 2), (3, 4));
|
||||
- 不要把矩阵链式比较 `::...` 和标量链式比较混写成同一种语法。
|
||||
- 不要把 `in` 和 `sqlin` 当成同一个概念。
|
||||
- 不要期待 `union2` 保留重复行。
|
||||
- 不要用集合运算去做“保留原始重复记录”的过滤任务。
|
||||
- 不要把二维结果集默认当成“按元素逐个比较”的集合运算。
|
||||
- 左侧数组要表达“这些值是否都属于右侧集合”时,用 `in`。
|
||||
- 左侧数组要表达“这一整行是否存在于右侧结果集”时,用 `sqlin`。
|
||||
- 不要用集合运算去做”保留原始重复记录”的过滤任务。
|
||||
- 不要把二维结果集默认当成”按元素逐个比较”的集合运算。
|
||||
- 左侧数组要表达”这些值是否都属于右侧集合”时,用 `in`。
|
||||
- 左侧数组要表达”这一整行是否存在于右侧结果集”时,用 `sqlin`。
|
||||
- `minus` 表达集合差集;如果任务要求保留左侧原始重复次数,改走 [13_resultset_and_filters.md](13_resultset_and_filters.md) 的过滤规则。
|
||||
- 不要在本页发明结果集过滤、TS-SQL 查询、写回语法或更大矩阵函数族。
|
||||
- 不要把普通 `array(...)` 自动升级成 `FMArray`;只有任务明确命中时才进入 [23_fmarray.md](23_fmarray.md)。
|
||||
- 不要把点前缀比较 `.>` 和矩阵链式比较 `::>` 混用;`.>` 返回逻辑数组,`::>` 是链式比较。
|
||||
- 不要以为非完全矩阵缺位会报错;默认当 `0` 处理。
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
2. 字段访问优先照本页明确的字符串键或结果集字段形态写。
|
||||
3. 复杂查询需求优先跳转到 [14_ts_sql.md](14_ts_sql.md),不要把查询语法硬塞进过滤函数。
|
||||
4. `in` / `sqlin` / `union2` / `intersect` / `minus` / `outersect` 这类去重型集合关系跳转到 [12_matrix_and_collections.md](12_matrix_and_collections.md)。
|
||||
5. 金融数据筛选要先确认数据来源;函数事实见 [../reference/catalog/datawarehouse.md](../reference/catalog/datawarehouse.md),项目字段和业务上下文回项目实际接口。
|
||||
5. 金融数据筛选要先确认数据来源;函数事实见 [../codegen/dotnet/datawarehouse/](../codegen/dotnet/datawarehouse/),项目字段和业务上下文回项目实际接口。
|
||||
6. 没有对应代码块时不要发明结果集/过滤写法。
|
||||
|
||||
## 核心规则
|
||||
|
||||
+597
-19
@@ -6,20 +6,22 @@
|
||||
是否含不可照写反例:是
|
||||
遇到不确定时:先按本页候选页继续判断;[13_resultset_and_filters.md](13_resultset_and_filters.md)、[12_matrix_and_collections.md](12_matrix_and_collections.md)、[23_fmarray.md](23_fmarray.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md)
|
||||
|
||||
这一篇是 TS-SQL 的唯一语法入口:内存数组查询、返回形态、字段访问、`where` / `group by` / `order by`、一维数组查询、多表 `join`、`thisGroup`、`thisRowIndex`、`refMaxOf` / `refMinOf` 都在这里收拢。
|
||||
这一篇是 TS-SQL 的唯一语法入口:内存数组查询、返回形态、字段访问、`where` / `group by` / `order by`、一维数组查询、多表 `join`(含 `left join`)、`insert` / `update` / `delete` 写回、`thisGroup`、`thisRowIndex`、`refMaxOf` / `refMinOf` 都在这里收拢。
|
||||
|
||||
## 本篇职责
|
||||
|
||||
回答“写 TS-SQL 查询时,怎样从最小 `select ... from ... end` 骨架开始,逐步处理筛选、分组、排序、多表联接、组内子查询和极值引用”。
|
||||
回答”写 TS-SQL 查询和写回时,怎样从最小 `select ... from ... end` 骨架开始,逐步处理筛选、分组、排序、多表联接(含 LEFT JOIN)、组内子查询、极值引用,以及如何用 `insert`/`update`/`delete` 修改内存数组”。
|
||||
|
||||
## 智能体 TS-SQL 判断流程
|
||||
|
||||
1. 先判断要写 `select`、`sselect`、`vselect`、`mselect`,还是 `join` / `thisGroup` / 极值引用。
|
||||
1. 先判断要写查询(`select`/`sselect`/`vselect`/`mselect`)还是写回(`insert`/`update`/`delete`)。
|
||||
2. 内存数组查询优先从 `select ... from source_rows end` 最小骨架起手。
|
||||
3. 二维结果集字段访问用 `["字段名"]`;多表查询字段访问用 `[表序号].["字段名"]`。
|
||||
4. 在一维数组上做 TS-SQL 时,优先使用 `thisRow` 和 `thisRowIndex`。
|
||||
5. 只想按已有结果集保留/排除行时跳到 [13_resultset_and_filters.md](13_resultset_and_filters.md);要做去重型集合关系时跳到 [12_matrix_and_collections.md](12_matrix_and_collections.md);要在 `FMArray` 上做查询或写回边界时跳到 [23_fmarray.md](23_fmarray.md)。
|
||||
6. 没有对应代码块时不要发明 TS-SQL 写法。
|
||||
5. 联接选 `join` / `left join` / `right join` / `full join` / `cross join` / 逗号联接;等值联接可用 `with(... on ...)` 优化。
|
||||
6. 聚集统一形态 `(Expr, Cond, N, MovingFirst, CacheId)`:条件聚集传 `Cond`,移动聚集传 `N`;分组后筛选用 `having`;自定义聚集用 `aggof`。
|
||||
7. 只想按已有结果集保留/排除行时跳到 [13_resultset_and_filters.md](13_resultset_and_filters.md);要做去重型集合关系时跳到 [12_matrix_and_collections.md](12_matrix_and_collections.md);要在 `FMArray` 上做查询或写回边界时跳到 [23_fmarray.md](23_fmarray.md)。
|
||||
8. 没有对应代码块时不要发明 TS-SQL 写法。
|
||||
|
||||
## 核心规则
|
||||
|
||||
@@ -29,11 +31,17 @@
|
||||
- 在内存二维结果集上,文档字段访问写法是 `["字段名"]`。
|
||||
- 在一维数组上做 TS-SQL 时,优先使用 `thisRow` 和 `thisRowIndex`。
|
||||
- `select` 返回二维结果,`sselect` 返回一维结果,`vselect` 返回单值,`mselect` 返回 `Matrix`。
|
||||
- `where`、`group by`、`order by` 可以直接接在 `from` 后面继续使用。
|
||||
- 多表 `join` 时,字段访问应写成 `[表序号].["字段名"]`。
|
||||
- `where`、`group by`、`order by` 可以直接接在 `from` 后面继续使用;`order by` 支持 `asc`/`desc` 与多列逗号分隔。
|
||||
- 分组后按聚集条件筛选用 `having`(`where` 不能用聚集);`having` 里用 `countof([字段])` 或 `countof(1)`,不要用 `countof(*)`。
|
||||
- 多表 `join` 时,字段访问应写成 `[表序号].["字段名"]`;`on` 可用 `and` 写多条件;`[表序号].*` 取整表列。
|
||||
- 联接类型:`left join` 保留左表、`right join` 保留右表、`full join` 保留双方、`cross join` 笛卡尔积、逗号联接等价于 `cross join`;不匹配处用 `nil` 填充。
|
||||
- `select` 列表支持 `distinct` 去重、`as 别名`、`as nil`(参与计算但不返回)、`起始列 to 结束列` 字段区间、`selectopt(位选项)`、`drange(区间/M of N)`。
|
||||
- 聚集函数统一形态 `Func(Expr[, Cond[, N[, MovingFirst[, CacheId]]]])`:条件聚集、移动聚集、多字段聚集、`refof(Expr, N)` 引用相对行;`aggof('名', Expr)` 调用自定义聚集回调。
|
||||
- `thisGroup` 不是普通值,而是分组后的子结果集;要通过子 `select` / `vselect` 的 `from thisGroup` 来访问。
|
||||
- `thisRowIndex` 在 `order by` 之后仍可返回原始行位置,而不是排序后的序号。
|
||||
- `thisRowIndex` 在 `order by` 之后仍可返回原始行位置;`thisOrder` 返回排序后的自然排名。
|
||||
- `refMaxOf(...)` 和 `refMinOf(...)` 可与 `maxOf(...)` / `minOf(...)` 配合,取极值所在行的另一列值。
|
||||
- `[@字段]` 返回该字段的数据类型字符串。
|
||||
- 写回语句 `insert` / `update` / `delete` 直接修改原内存数组,不返回新数组。
|
||||
- 访问金融表、时间序列或业务数据源时,语法和业务语义要分开看;本页只讲语言层查询骨架。
|
||||
|
||||
## 可直接照写示例
|
||||
@@ -218,8 +226,8 @@ source_rows := array(
|
||||
("A": 2, "B": 1, "Name": "y"),
|
||||
("A": 1, "B": 2, "Name": "z")
|
||||
);
|
||||
group_result := select ["A"], maxb := maxOf(["B"]) as "MaxB",
|
||||
vselect ["Name"] from thisGroup where ["B"] = maxb end as "TopName"
|
||||
group_result := select ["A"], max_b := maxOf(["B"]) as "MaxB",
|
||||
vselect ["Name"] from thisGroup where ["B"] = max_b end as "TopName"
|
||||
from source_rows
|
||||
group by ["A"]
|
||||
order by ["A"]
|
||||
@@ -270,17 +278,576 @@ min_ref_result := select minOf([0]) as "MinA", refMinOf([1]) as "RefB" from sour
|
||||
- `min_ref_result` 只有一行,结果是 `(2,20)`
|
||||
- 说明 `refMaxOf([1])` 取到了 `[0]` 最大值所在行的 `[1]`,`refMinOf([1])` 取到了 `[0]` 最小值所在行的 `[1]`
|
||||
|
||||
### `LEFT JOIN` 多表联接
|
||||
|
||||
`left join` 保留左表所有行,右表不匹配时用 `nil` 填充:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
left_rows := array(("k": 1, "va": "a1"), ("k": 2, "va": "a2"));
|
||||
right_rows := array(("k": 1, "vb": "b1"), ("k": 3, "vb": "b3"));
|
||||
result := select [1].["va"], [2].["vb"]
|
||||
from left_rows left join right_rows
|
||||
on [1].["k"] = [2].["k"]
|
||||
end;
|
||||
writeLn("行数:", mrows(result));
|
||||
writeLn("(0,0):", result[0]["va"]);
|
||||
writeLn("(0,1):", result[0]["vb"]);
|
||||
writeLn("(1,0):", result[1]["va"]);
|
||||
writeLn("(1,1):", result[1]["vb"]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
行数: 2
|
||||
(0,0): a1
|
||||
(0,1): b1
|
||||
(1,0): a2
|
||||
(1,1): nil
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `left join` 保留左表所有行(`k=1` 和 `k=2`)
|
||||
- 右表 `k=2` 不存在,对应列用 `nil` 填充
|
||||
- `on` 子句指定联接条件,用 `[1].["k"] = [2].["k"]` 匹配键
|
||||
- 其他联接类型:`right join`(保留右表)、`full join`(保留双方)、`cross join`(笛卡尔积)
|
||||
|
||||
### JOIN 家族其余形态
|
||||
|
||||
`right join` / `full join` 的不匹配行同样用 `nil` 填充:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array(("id": "01", "en": 90), ("id": "02", "en": 80));
|
||||
b := array(("id": "01", "math": 70), ("id": "05", "math": 50));
|
||||
right_result := select [1].["id"], [2].["math"] from a right join b on [1].["id"] = [2].["id"] end;
|
||||
full_result := select [1].["id"], [2].["math"] from a full join b on [1].["id"] = [2].["id"] end;
|
||||
writeLn("right行数:", mrows(right_result));
|
||||
writeLn("full行数:", mrows(full_result));
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
right行数: 2
|
||||
full行数: 3
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `right join` 保留右表所有行,左表无匹配的记录里,取自左表的字段为 `nil`(上例右表 `id=05` 那行 `[1].["id"]` 为 `nil`)
|
||||
- `full join` 保留双方所有行,任一侧无匹配的字段用 `nil` 填充(上例既有左表独占的 `02`,也有右表独占的 `05`)
|
||||
|
||||
`cross join` 是笛卡尔积,不带 `on`;等价的逗号联接可带 `where`:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array(("id": "01", "en": 90), ("id": "02", "en": 80));
|
||||
b := array(("id": "01", "math": 70), ("id": "05", "math": 50));
|
||||
cross_result := select [1].["id"], [2].["id"] from a cross join b end;
|
||||
comma_result := select [1].["id"] from a, b where [1].["id"] = [2].["id"] end;
|
||||
writeLn("cross行数:", mrows(cross_result));
|
||||
writeLn("comma行数:", mrows(comma_result));
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
cross行数: 4
|
||||
comma行数: 1
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `cross join` 不写 `on`,产生左右两表的全组合(2 × 2 = 4 行)
|
||||
- `from A, B where ...` 是等价的逗号联接写法,用 `where` 表达匹配条件
|
||||
|
||||
`with(... on ...)` 是优化联接:把 `on` 的 N×M 匹配复杂度降到 N+M,多个等值约束用逗号分隔:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array(("id": "01", "en": 90), ("id": "03", "en": 85));
|
||||
b := array(("id": "01", "math": 70), ("id": "03", "math": 60), ("id": "05", "math": 50));
|
||||
result := select [1].["id"], [2].["math"] from a join b with([1].["id"] on [2].["id"]) end;
|
||||
writeLn("行数:", mrows(result));
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
行数: 2
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `join B with(左表达式组 on 右表达式组)` 只支持等值约束,靠哈希把复杂度降到 N+M
|
||||
- 多个等值约束写成 `with([1].["id"], [1].["cls"] on [2].["id"], [2].["cls"])`
|
||||
- 需要非等值条件(`>`、`<`)时回到普通 `join ... on`
|
||||
|
||||
`on` 支持多条件 `and`,`[表序号].*` 取整表所有列:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array(("id": "01", "en": 90), ("id": "03", "en": 85));
|
||||
b := array(("id": "01", "math": 70), ("id": "03", "math": 95));
|
||||
result := select [1].* from a join b on [1].["id"] = [2].["id"] and [1].["en"] > [2].["math"] end;
|
||||
writeLn("行数:", mrows(result));
|
||||
writeLn("(0,0):", result[0]["id"]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
行数: 1
|
||||
(0,0): 01
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `on` 后面可以用 `and` 串联多个条件
|
||||
- `[1].*` 返回第一个表的所有列;三表以上时链式写 `join C on ...`
|
||||
|
||||
### `INSERT` 写回
|
||||
|
||||
`insert into` 向内存数组插入新行:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array(("id": "x"));
|
||||
insert into a insertfields(["id"]) values("y");
|
||||
writeLn("行数:", mrows(a));
|
||||
writeLn("(0,0):", a[0]["id"]);
|
||||
writeLn("(1,0):", a[1]["id"]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
行数: 2
|
||||
(0,0): x
|
||||
(1,0): y
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `insert into 数组变量` 直接修改原数组
|
||||
- `insertfields([字段列表])` 指定要插入的字段
|
||||
- `values(...)` 提供对应值,可以写多组 `values`、`values` 实现批量插入
|
||||
|
||||
批量插入可以直接跟一个同结构数组,`insertfields` 也支持一次给多字段赋值:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array(("id": "01", "cls": "A"));
|
||||
rows := array(("id": "09", "cls": "C"));
|
||||
insert into a rows;
|
||||
insert into a insertfields(["id"], ["cls"]) values("07", "B");
|
||||
writeLn("行数:", mrows(a));
|
||||
writeLn(a[1]["id"], a[1]["cls"]);
|
||||
writeLn(a[2]["id"], a[2]["cls"]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
行数: 3
|
||||
09C
|
||||
07B
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `insert into a rows;` 把整个 `rows` 数组的行批量追加进 `a`
|
||||
- `insertfields(["id"], ["cls"]) values("07", "B")` 一次插入多字段
|
||||
|
||||
### `UPDATE` 写回
|
||||
|
||||
`update` 修改符合条件的行:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array(("id": "x", "v": 1), ("id": "y", "v": 2));
|
||||
update a set ["v"] = 99 where ["id"] = "y" end;
|
||||
writeLn(a[0]["v"]);
|
||||
writeLn(a[1]["v"]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
1
|
||||
99
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `update 数组变量 set [字段] = 新值` 直接修改原数组
|
||||
- `where` 子句筛选要更新的行
|
||||
- 可以同时更新多个字段:`set ["v1"] = 10, ["v2"] = 20`
|
||||
|
||||
`set` 一个不存在的列会自动新增该列;`set thisrow = ...` 可以整行替换(一维数组上尤其常用):
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array(("id": "01", "en": 90), ("id": "02", "en": 80));
|
||||
update a set ["total"] = ["en"] + 1 end;
|
||||
r := array(1, 2, 3);
|
||||
update r set thisrow = thisrow * 10 end;
|
||||
writeLn(a[0]["total"]);
|
||||
writeLn(r[0], r[1], r[2]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
91
|
||||
102030
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `set ["total"] = ...` 中 `total` 原本不存在,执行后自动作为新列加到每一行
|
||||
- `set thisrow = thisrow * 10` 用当前行整体做表达式并写回;一维数组上 `thisrow` 就是元素本身
|
||||
|
||||
### `DELETE` 写回
|
||||
|
||||
`delete` 删除符合条件的行:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array(("id": "x"), ("id": "y"));
|
||||
delete from a where ["id"] = "x";
|
||||
writeLn("行数:", mrows(a));
|
||||
writeLn("(0,0):", a[0]["id"]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
行数: 1
|
||||
(0,0): y
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `delete from 数组变量 where 条件` 删除符合条件的行
|
||||
- 直接修改原数组
|
||||
- 省略 `where` 会删除所有行
|
||||
|
||||
`deleteopt(Option)` 控制删除后是否重排下标:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array(("cls": "A"), ("cls": "A"), ("cls": "B"), ("cls": "B"));
|
||||
delete deleteopt(1) from a where ["cls"] = "A";
|
||||
writeLn(mrows(a));
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
2
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `deleteopt(0)`(默认)删除后重排剩余行下标
|
||||
- `deleteopt(1)` 删除后保留原始下标,不重排
|
||||
|
||||
### `distinct` 结果集去重
|
||||
|
||||
`select distinct` 对结果集去重;聚集函数内也可用 `distinct` 前缀:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array(("cls": "A", "en": 90), ("cls": "A", "en": 80), ("cls": "B", "en": 85));
|
||||
distinct_rows := select distinct ["cls"] from a end;
|
||||
distinct_sum := vselect sumof(distinct ["en"]) from a end;
|
||||
writeLn(mrows(distinct_rows));
|
||||
writeLn(distinct_sum);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
2
|
||||
255
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `select distinct [字段]` 折叠重复行
|
||||
- `sumof(distinct [字段])` 只对不同值求和:`90 + 80 + 85 = 255`
|
||||
|
||||
### `as` 别名、`as nil` 与字段区间
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array(("id": "01", "cls": "A", "en": 90), ("id": "02", "cls": "B", "en": 80));
|
||||
alias_rows := select ["en"] as "score" from a end;
|
||||
nil_rows := select ["id"], ["en"] * 2 as nil from a end;
|
||||
range_rows := select 0 to 1 from a end;
|
||||
writeLn(alias_rows[0]["score"]);
|
||||
writeLn(mcols(nil_rows));
|
||||
writeLn(mcols(range_rows));
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
90
|
||||
1
|
||||
2
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `字段 as "别名"` 给结果列改名
|
||||
- `表达式 as nil` 让该列只参与临时计算,不出现在结果集里(上例 `nil_rows` 只剩 `id` 一列)
|
||||
- `StartIndex to EndIndex` 在选择列表里取列区间;`0 to 1` 返回第 0、1 两列
|
||||
|
||||
### `drange` 取行区间
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array(("id": "01"), ("id": "02"), ("id": "03"), ("id": "04"));
|
||||
head_rows := select drange(0 to 1) * from a end;
|
||||
tail_rows := select drange(-2 to -1) * from a end;
|
||||
part_rows := select drange(1 of 2) * from a end;
|
||||
writeLn(mrows(head_rows));
|
||||
writeLn(tail_rows[0]["id"]);
|
||||
writeLn(mrows(part_rows));
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
2
|
||||
03
|
||||
2
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `drange(begin to end)` 取行区间;负数从末尾计(`-1` 是最后一行)
|
||||
- `drange(M of N)` 把结果集等分成 N 份,取第 M 份
|
||||
|
||||
### `selectopt` 位选项
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array(("en": 90), ("en": 80), ("en": 85), ("en": 85));
|
||||
opt_rows := select selectopt(2) ["en"] from a end;
|
||||
writeLn(dataType(opt_rows));
|
||||
writeLn(opt_rows[0]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
4
|
||||
90
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `selectopt(N)` 用位组合改变返回形态;`selectopt(2)` 让 `select` 返回一维数组(不再是二维结果集)
|
||||
- 常用位:`1`=单值、`2`=一维、`4`=Matrix、`16`=多字段聚集保留原名、`64`=MovingFirst 变换
|
||||
|
||||
### 条件聚集、移动聚集与 `refof`
|
||||
|
||||
聚集函数统一支持 `(Expr, BoolConditionExp, N, MovingFirst, CacheId)` 形态:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array(("en": 90), ("en": 80), ("en": 85), ("en": 85));
|
||||
cond_sum := vselect sumof(["en"], ["en"] >= 85) from a end;
|
||||
moving := select avgof(["en"], true, 2, true) from a end;
|
||||
ref_prev := select ["en"], refof(["en"], 1) from a end;
|
||||
writeLn(cond_sum);
|
||||
writeLn(moving[2]["Expr1"]);
|
||||
writeLn(ref_prev[1]["Expr1"]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
260
|
||||
82.5
|
||||
90
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- 条件聚集:`sumof(表达式, 布尔条件)` 只统计条件为真的行(`90 + 85 + 85 = 260`)
|
||||
- 移动聚集:`avgof(表达式, 条件, N, MovingFirst)` 取当前行往前 N 条的滑动统计
|
||||
- `refof(表达式, N)` 引用前 N 行的值(`N` 为负则往后);首行无前值时返回 `0`
|
||||
|
||||
### `group by ... having`
|
||||
|
||||
`having` 用聚集条件筛选分组(`where` 不能用聚集):
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array(("cls": "A", "en": 90), ("cls": "A", "en": 80), ("cls": "B", "en": 85));
|
||||
having_rows := select ["cls"] from a group by ["cls"] having countof(["cls"]) > 1 end;
|
||||
writeLn(mrows(having_rows));
|
||||
writeLn(having_rows[0]["cls"]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
1
|
||||
A
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `having 聚集条件` 在分组后筛选(上例只保留成员数大于 1 的 `A` 组)
|
||||
- `having` 里的计数用 `countof([字段])` 或 `countof(1)`
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
|
||||
```text
|
||||
having_rows := select ["cls"] from a group by ["cls"] having countof(*) > 1 end;
|
||||
```
|
||||
|
||||
`countof(*)` 这种带 `*` 的写法不成立,会报 `CountOf ( not found`。计数改用 `countof([字段])` 或 `countof(1)`。
|
||||
|
||||
### `thisOrder` 与多列 `order by`
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array(("id": "01", "en": 90), ("id": "02", "en": 80), ("id": "03", "en": 85), ("id": "04", "en": 85));
|
||||
order_rows := select ["id"], thisOrder as "ord" from a order by ["en"] end;
|
||||
desc_rows := select ["id"] from a order by ["en"] desc end;
|
||||
writeLn(order_rows[0]["id"], ",", order_rows[0]["ord"]);
|
||||
writeLn(desc_rows[0]["id"]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
02,1
|
||||
01
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `thisOrder` 返回排序后的自然排名(从 1 起,值相同则同名次,名次可不连续)
|
||||
- `order by [字段] desc` 降序;多列排序用逗号分隔:`order by ["cls"] asc, ["en"] desc`
|
||||
- `thisOrder` 与 `thisRowIndex` 不同:后者返回排序前的原始行位置
|
||||
|
||||
### `refsof` 引用上级结果集
|
||||
|
||||
在嵌套子查询里,`refsof(Exp, UpLevel)` 用上 N 级结果集计算 `Exp`:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array(("id": "01", "en": 90), ("id": "02", "en": 80));
|
||||
r := select ["id"], (vselect refsof(["en"], 1) from a end) as "up" from a end;
|
||||
writeLn(r[0]["id"], ",", r[0]["up"]);
|
||||
writeLn(r[1]["id"], ",", r[1]["up"]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
01,90
|
||||
02,80
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `refsof(表达式, 1)` 在内层子查询里引用上一级(外层)结果集当前行的值
|
||||
- 数字越大引用越靠外层;脱离嵌套单独使用会报 `no result set for reference`
|
||||
|
||||
### `[@Field]` 取字段类型
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array(("id": "01", "en": 90), ("id": "02", "en": 80));
|
||||
t := select ["id"], [@"en"] from a end;
|
||||
writeLn(t[0]["Expr1"]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
integer
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `[@字段名]` 返回该字段的数据类型名(字符串),可用于 select 列表与 update set
|
||||
|
||||
### `aggof` 自定义聚集扩展
|
||||
|
||||
> 代码块身份:仅服务端可执行示例
|
||||
> 本地 `TSL.exe` 会报 `AggOf Init Error`;下例在服务端(pyTSL)验证通过。
|
||||
|
||||
`aggof('名称', 表达式)` 调用一个自定义回调函数做聚集:
|
||||
|
||||
代码块身份:仅服务端可执行示例
|
||||
|
||||
```tsl
|
||||
Table1 := array(("C": 1), ("C": 2), ("C": 3), ("C": 4), ("C": 5));
|
||||
return vselect aggof('AggSumSample', ['C']) from Table1 end;
|
||||
|
||||
function AggSumSample(Flag, Value);
|
||||
begin
|
||||
if Flag = 0 then
|
||||
begin
|
||||
sysParams['SumSample'] := 0;
|
||||
return true;
|
||||
end
|
||||
else if Flag = 1 then
|
||||
begin
|
||||
sysParams['SumSample'] := sysParams['SumSample'] + Value;
|
||||
return true;
|
||||
end
|
||||
else
|
||||
return sysParams['SumSample'];
|
||||
end;
|
||||
```
|
||||
|
||||
说明(上例返回 `15`):
|
||||
|
||||
- 回调签名固定为 `function Name(Flag, Value)`
|
||||
- `Flag=0` 初始化(`Value` 为真表示 `distinct`),返回 `true`/`false` 表示成败
|
||||
- `Flag=1` 每行数据,`Value` 是当前行表达式的值,返回 `true`/`false`
|
||||
- `Flag=2` 结束,返回最终聚集结果
|
||||
- 状态用 `sysParams[...]` 缓存,不要用 `static`
|
||||
|
||||
## 本页不生成的范围
|
||||
|
||||
- `with on`
|
||||
- `left join` / `right join` / `full join`
|
||||
- `RefsOf`
|
||||
- `insert` / `update` / `delete`
|
||||
- `TSQLInsert` / `TSQLSetValue` / `TSQLBatchInsert`
|
||||
- `TSQLEdit` / `TSQLPost` / `TSQLFinal`
|
||||
- 面向 SQL 表、业务表或时间序列的数据查询与写回
|
||||
- `TSQLInsert` / `TSQLSetValue` / `TSQLBatchInsert` / `TSQLEdit` / `TSQLPost` / `TSQLFinal` 对象被 TS-SQL 查询的回调机制
|
||||
- 面向 SQL 表、业务表或时间序列的数据查询与写回(`marketTable` / `infoTable` / `tradeTable` / `sqlTable` / `hugeSqlTable` 等数据源)
|
||||
|
||||
这些内容不作为本页可生成事实;业务数据源先查 [../reference/catalog/datawarehouse.md](../reference/catalog/datawarehouse.md)、[../modules/pytsl_api.md](../modules/pytsl_api.md) 或项目实际接口。
|
||||
这些内容不作为本页可生成事实;业务数据源先查 [../codegen/dotnet/datawarehouse/](../codegen/dotnet/datawarehouse/)、[../modules/pytsl_api.md](../modules/pytsl_api.md) 或项目实际接口。
|
||||
|
||||
## 默认生成模板
|
||||
|
||||
@@ -301,7 +868,18 @@ query_result := select * from source_rows end;
|
||||
- 处理一维数组时直接把 `[0]` 当成稳定列访问。
|
||||
- 把 `thisGroup` 当成普通字段或普通变量。
|
||||
- 把排序后的 `thisRowIndex` 误当成排序序号。
|
||||
- 把 `with on`、写回接口和时间序列缓存写进默认模板。
|
||||
- 在 `left join` 时省略 `on` 子句或不用 `[表序号].["字段"]` 形式。
|
||||
- 在 `insert` 时漏掉 `insertfields` 或字段数与值数不匹配。
|
||||
- 期望 `update`/`delete` 返回新数组;它们直接修改原数组。
|
||||
- 用 `countof(*)` 数行数;`*` 星号形式不被支持,改用 `countof([字段])` 或 `countof(1)`。
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
|
||||
```text
|
||||
n := vselect countof(*) from source_rows end;
|
||||
```
|
||||
|
||||
`countof(*)` 会报 `CountOf ( not found`。数行数改用 `countof([字段])` 或 `countof(1)`。
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
- `debugRunEnv(0)` 和 `debugRunEnv(1)` 可直接调用;它们面向调试客户端的副作用,不作为本页输出事实。
|
||||
- `debugRunEnvDo Func(...)` 可直接写,并且会返回被调用函数的结果。
|
||||
- `mtic` 会生成一个计时起点;`mtoc` 和 `mtoc(tick)` 都会返回秒数。
|
||||
- `setProfiler(...)` 和 `getProfilerInfo(...)` 的参数规格见 [../reference/catalog/system.md](../reference/catalog/system.md);本页只保留性能分析器行为示例。
|
||||
- `setProfiler(...)` 和 `getProfilerInfo(...)` 的参数规格见 [../codegen/builtin/system.md](../codegen/builtin/system.md);本页只保留性能分析器行为示例。
|
||||
- `setProfiler(7)` 配合 `getProfilerInfo(1)`,可以在不弹窗的情况下拿到性能分析器信息。
|
||||
- `__line__` 会返回所在代码行号。
|
||||
- `__stack_frame` 会返回调用栈帧数组;最小 `toStn(...)` 观察结果里,每一项是 `(line, "function")` 这一类二元组。
|
||||
@@ -108,9 +108,9 @@ writeLn("before");
|
||||
a := Inner(3);
|
||||
writeLn("after");
|
||||
|
||||
function Inner(bb);
|
||||
function Inner(value);
|
||||
begin
|
||||
debugReturn bb;
|
||||
debugReturn value;
|
||||
end;
|
||||
```
|
||||
|
||||
@@ -144,8 +144,8 @@ writeLn(1);
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
r := debugRunEnvDo Demo(2);
|
||||
writeLn(r);
|
||||
result := debugRunEnvDo Demo(2);
|
||||
writeLn(result);
|
||||
|
||||
function Demo(x);
|
||||
begin
|
||||
@@ -165,17 +165,17 @@ end;
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
t1 := mtic;
|
||||
s := 0;
|
||||
tick1 := mtic;
|
||||
sum := 0;
|
||||
for i := 0 to 9999 do
|
||||
s := s + i;
|
||||
te1 := mtoc(t1);
|
||||
t2 := mtic;
|
||||
sum := sum + i;
|
||||
elapsed1 := mtoc(tick1);
|
||||
tick2 := mtic;
|
||||
for j := 0 to 9999 do
|
||||
s := s + j;
|
||||
te2 := mtoc;
|
||||
writeLn(te1 >= 0);
|
||||
writeLn(te2 >= 0);
|
||||
sum := sum + j;
|
||||
elapsed2 := mtoc;
|
||||
writeLn(elapsed1 >= 0);
|
||||
writeLn(elapsed2 >= 0);
|
||||
```
|
||||
|
||||
结果说明:
|
||||
@@ -189,9 +189,9 @@ writeLn(te2 >= 0);
|
||||
|
||||
```tsl
|
||||
setProfiler(7);
|
||||
a := 99;
|
||||
b := intToStr(a);
|
||||
c := rand(10, 1);
|
||||
value := 99;
|
||||
str := intToStr(value);
|
||||
random := rand(10, 1);
|
||||
info := getProfilerInfo(1);
|
||||
writeLn(ifArray(info));
|
||||
writeLn(length(info) > 0);
|
||||
@@ -210,8 +210,8 @@ writeLn(length(info) > 0);
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := __line__;
|
||||
writeLn(a);
|
||||
line_number := __line__;
|
||||
writeLn(line_number);
|
||||
```
|
||||
|
||||
结果说明:
|
||||
@@ -224,8 +224,8 @@ writeLn(a);
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
s := Outer();
|
||||
writeLn(toStn(s));
|
||||
stack := Outer();
|
||||
writeLn(toStn(stack));
|
||||
|
||||
function Inner();
|
||||
begin
|
||||
|
||||
@@ -170,6 +170,30 @@ writeLn(1);
|
||||
- 输出 `1`
|
||||
- 说明未命中的条件编译分支不会参与脚本编译
|
||||
|
||||
### `{$CompileOption}` 编译选项
|
||||
|
||||
`{$CompileOption}` 用于设置编译期开关,改变编译器的默认行为:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
{$CompileOption optimize=1}
|
||||
echo 1 + 1;
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
2
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `{$CompileOption optimize=1}` 开启优化
|
||||
- 编译选项从出现位置开始生效,直到源文件结束或被其他选项覆盖
|
||||
- 常见选项包括 `optimize`、`buffermode`、`DebugInfo` 等
|
||||
- 编译选项细节以项目工具链和实际编译命令为准。
|
||||
|
||||
### 参数默认传递开关
|
||||
|
||||
`{$varByRef-}` 与 `{$varByRef+}`:
|
||||
@@ -190,23 +214,23 @@ r := 1;
|
||||
TouchRestored(r);
|
||||
writeLn(r);
|
||||
|
||||
function TouchDefault(a);
|
||||
function TouchDefault(value);
|
||||
begin
|
||||
a := 9;
|
||||
value := 9;
|
||||
end;
|
||||
{$varByRef-}
|
||||
function TouchValue(a);
|
||||
function TouchValue(value);
|
||||
begin
|
||||
a := 8;
|
||||
value := 8;
|
||||
end;
|
||||
function TouchForcedVar(var a);
|
||||
function TouchForcedVar(var value);
|
||||
begin
|
||||
a := 7;
|
||||
value := 7;
|
||||
end;
|
||||
{$varByRef+}
|
||||
function TouchRestored(a);
|
||||
function TouchRestored(value);
|
||||
begin
|
||||
a := 6;
|
||||
value := 6;
|
||||
end;
|
||||
```
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
- `dataType(z)` 对复数返回 `41`,`ifComplex(z)` 对复数返回 `1`。
|
||||
- `real`、`imag`、`conj`、`abs` 都可用于复数。
|
||||
- 实数 `x` 与复数 `x + 0j` 的相等比较结果为真。
|
||||
- 复数支持四则运算 `+` / `-` / `*` / `/`,可与实数混合运算;矩阵乘用 `:*`。
|
||||
- `complex(array(...), imag)` 会返回 `Array`;`complex(fmarray..., imag)` 会返回 `FMArray`,并且其单元格类型是 `41`。
|
||||
|
||||
## 可直接照写示例
|
||||
@@ -138,14 +139,14 @@ writeLn(nan = nan);
|
||||
|
||||
```tsl
|
||||
writeLn(a);
|
||||
h := new Holder();
|
||||
writeLn(h.value = nil);
|
||||
holder := new Holder();
|
||||
writeLn(holder.Value = nil);
|
||||
arr := array();
|
||||
writeLn(arr[0] = nil);
|
||||
|
||||
type Holder = class
|
||||
public
|
||||
value;
|
||||
Value;
|
||||
end;
|
||||
```
|
||||
|
||||
@@ -153,7 +154,7 @@ end;
|
||||
|
||||
- 依次输出 `0`、`1`、`1`
|
||||
- 说明未初始化普通变量默认是整数 `0`
|
||||
- 说明类成员默认值是 `nil`
|
||||
- 说明类成员默认值是 `nil`(`holder.Value`)
|
||||
- 也说明空数组读取尚未赋值的下标时,结果是 `nil`
|
||||
|
||||
`nil` 的显式判定与加法边界:
|
||||
@@ -304,6 +305,46 @@ writeLn(f[0], ',', f[1], ',', f[2]);
|
||||
- 上述复数 `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`。
|
||||
|
||||
复数最短骨架:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
@@ -113,10 +113,10 @@ function TickCdecl(): int64; cdecl; external "kernel32.dll" name "GetTickCount64
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
t1 := Tick64();
|
||||
tick_before := Tick64();
|
||||
SleepMs(20);
|
||||
t2 := Tick64();
|
||||
writeLn(t2 >= t1);
|
||||
tick_after := Tick64();
|
||||
writeLn(tick_after >= tick_before);
|
||||
|
||||
function Tick64(): int64; stdcall; external "kernel32.dll" name "GetTickCount64";
|
||||
procedure SleepMs(ms: integer); stdcall; external "kernel32.dll" name "Sleep";
|
||||
@@ -132,15 +132,15 @@ procedure SleepMs(ms: integer); stdcall; external "kernel32.dll" name "Sleep";
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
h := LoadLibraryA("kernel32.dll");
|
||||
fp := GetProcAddress(h, "GetTickCount64");
|
||||
f := function(): int64; stdcall; external fp;
|
||||
writeLn(h <> nil);
|
||||
writeLn(fp <> nil);
|
||||
writeLn(##f() > 0);
|
||||
module_handle := LoadLibraryA("kernel32.dll");
|
||||
func_ptr := GetProcAddress(module_handle, "GetTickCount64");
|
||||
wrapped_func := function(): int64; stdcall; external func_ptr;
|
||||
writeLn(module_handle <> nil);
|
||||
writeLn(func_ptr <> nil);
|
||||
writeLn(##wrapped_func() > 0);
|
||||
|
||||
function LoadLibraryA(s: string): pointer; stdcall; external "kernel32.dll" name "LoadLibraryA";
|
||||
function GetProcAddress(hModule: pointer; lpProcName: string): pointer; stdcall; external "kernel32.dll" name "GetProcAddress";
|
||||
function LoadLibraryA(lib_name: string): pointer; stdcall; external "kernel32.dll" name "LoadLibraryA";
|
||||
function GetProcAddress(module_handle: pointer; proc_name: string): pointer; stdcall; external "kernel32.dll" name "GetProcAddress";
|
||||
```
|
||||
|
||||
结果说明:
|
||||
@@ -155,17 +155,17 @@ function GetProcAddress(hModule: pointer; lpProcName: string): pointer; stdcall;
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
d := new Demo();
|
||||
writeLn(d.Run());
|
||||
demo := new Demo();
|
||||
writeLn(demo.Run());
|
||||
|
||||
type Demo = class
|
||||
public
|
||||
const kernel_dll = "kernel32.dll";
|
||||
const kKernelDll = "kernel32.dll";
|
||||
function Run();
|
||||
begin
|
||||
return TickConst() > 0;
|
||||
end;
|
||||
function TickConst(): int64; stdcall; external kernel_dll name "GetTickCount64";
|
||||
function TickConst(): int64; stdcall; external kKernelDll name "GetTickCount64";
|
||||
end;
|
||||
```
|
||||
|
||||
@@ -189,10 +189,10 @@ function TickFromExpr(): int64; stdcall; external "kernel32"$"."$"dll" name "Get
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
fp := makeInstance(thisFunction(Add), "cdecl", 0);
|
||||
f := function(a: integer; b: integer): integer; external fp;
|
||||
writeLn(fp <> nil);
|
||||
writeLn(##f(3, 4));
|
||||
func_ptr := makeInstance(thisFunction(Add), "cdecl", 0);
|
||||
wrapped_func := function(a: integer; b: integer): integer; external func_ptr;
|
||||
writeLn(func_ptr <> nil);
|
||||
writeLn(##wrapped_func(3, 4));
|
||||
|
||||
function Add(a: integer; b: integer): integer;
|
||||
begin
|
||||
@@ -212,19 +212,19 @@ end;
|
||||
|
||||
```tsl
|
||||
setGlobalCache("THREAD_TEST_KEY", 0);
|
||||
fp := makeInstance(thisFunction(Worker), "cdecl", 1);
|
||||
h := CreateThread(nil, nil, fp, nil, 0, tid);
|
||||
writeLn(fp <> nil);
|
||||
writeLn(h <> nil);
|
||||
writeLn(WaitForSingleObject(h, 5000) >= 0);
|
||||
getGlobalCache("THREAD_TEST_KEY", v);
|
||||
writeLn(v);
|
||||
CloseHandle(h);
|
||||
worker_ptr := makeInstance(thisFunction(Worker), "cdecl", 1);
|
||||
thread_handle := CreateThread(nil, nil, worker_ptr, nil, 0, thread_id);
|
||||
writeLn(worker_ptr <> nil);
|
||||
writeLn(thread_handle <> nil);
|
||||
writeLn(WaitForSingleObject(thread_handle, 5000) >= 0);
|
||||
getGlobalCache("THREAD_TEST_KEY", result_value);
|
||||
writeLn(result_value);
|
||||
CloseHandle(thread_handle);
|
||||
|
||||
function CreateThread(attr: pointer; size: pointer; addr: pointer; p: pointer; flag: Integer; var thread_id: Integer): pointer; stdcall; external "kernel32.dll" name "CreateThread";
|
||||
function WaitForSingleObject(h: pointer; timeout: Integer): Integer; stdcall; external "kernel32.dll" name "WaitForSingleObject";
|
||||
function CloseHandle(h: pointer): Integer; stdcall; external "kernel32.dll" name "CloseHandle";
|
||||
function Worker(p: pointer): integer;
|
||||
function WaitForSingleObject(handle: pointer; timeout: Integer): Integer; stdcall; external "kernel32.dll" name "WaitForSingleObject";
|
||||
function CloseHandle(handle: pointer): Integer; stdcall; external "kernel32.dll" name "CloseHandle";
|
||||
function Worker(param: pointer): integer;
|
||||
begin
|
||||
setGlobalCache("THREAD_TEST_KEY", 1);
|
||||
return 1;
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
- 直接写 `DemoUnit.Member` 时,可以读到 `interface` 和 `implementation` 里的常量、变量。
|
||||
- `findFunction("DemoUnit")` 拿到的是 `unit` 对象入口;本页只把它稳定暴露 `interface` 成员写成文档事实。
|
||||
- `DemoUnit.var_name := value` 这种限定赋值不作为可写事实;如果要改 `unit` 状态,应导出函数或方法来改。
|
||||
- `tslfilename()` 的参数规格见 [../reference/catalog/system.md](../reference/catalog/system.md);本页只保留它返回正在执行的 `.tsl` 主脚本完整路径这一行为事实。
|
||||
- `tslfilename()` 的参数规格见 [../codegen/builtin/system.md](../codegen/builtin/system.md);本页只保留它返回正在执行的 `.tsl` 主脚本完整路径这一行为事实。
|
||||
- `namespace "DemoNS";` 会选择 `Hello@DemoNS.tsf` 这类命名空间函数文件。
|
||||
- `tsl.conf` 的 `[system] Namespace=...` 可以设置默认命名空间;脚本里的 `namespace "..."` 会覆盖配置值。
|
||||
- 当全局 `Hello.tsf` 和 `Hello@StmtNS.tsf` 同时存在时,启用 `StmtNS` 后会优先命中命名空间版本。
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
2. 普通对象创建、普通方法调用、类声明和继承都回到 [08_objects_and_classes.md](08_objects_and_classes.md),不要把 `findClass(...)` / `createObject(...)` 当默认写法。
|
||||
3. 确实命中反射时,入口优先照 `findClass`、`findFunction`、`thisFunction`、`findOverLoad` 等文档明确示例写。
|
||||
4. 访问弱引用前先做 `checkWeakRef(...)` 判定,不要假设失效弱引用安全返回 `nil`。
|
||||
5. 类内 `weakRef;` / `autoRef;` 段落式写法属于反例,不要照写。
|
||||
5. 类内段落式 `weakRef` / `autoRef`(不带分号)是合法的成员弱引用开关;只有带分号的 `weakRef;` / `autoRef;` 才报 `invalid class definition`。
|
||||
6. 函数值调用边界回看函数页,避免把函数指针直接当普通函数调用。
|
||||
7. 没有对应代码块时不要发明对象运行时/反射/弱引用写法。
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
- 对已经失效的弱引用直接调用 `weakref_get(w)` 会运行报错,不要把它当成“安全返回 nil”的接口。
|
||||
- 类成员上的 `[weakRef] field;` 和 `[autoRef] field;` 可以通过。
|
||||
- `[weakRef]` 成员不会阻止对象析构;强引用释放后,对象会正常销毁。
|
||||
- 类内段落式 `weakRef;` / `autoRef;` 不作为可写事实,错误信息包含 `invalid class definition`。
|
||||
- 类内段落式 `weakRef` / `autoRef`(不带分号)像 `public` / `private` 一样切换后续成员的弱引用属性,可写;只有带分号的 `weakRef;` / `autoRef;` 才报 `invalid class definition`。
|
||||
|
||||
## 可直接照写示例
|
||||
|
||||
@@ -84,12 +84,12 @@ end;
|
||||
```tsl
|
||||
classA := findClass("A");
|
||||
obj := new A();
|
||||
writeLn(classA.FucA());
|
||||
writeLn(classA.FuncA());
|
||||
writeLn(obj is classA);
|
||||
|
||||
type A = class
|
||||
public
|
||||
class function FucA();
|
||||
class function FuncA();
|
||||
begin
|
||||
return "ClassA";
|
||||
end;
|
||||
@@ -110,18 +110,18 @@ end;
|
||||
```tsl
|
||||
objb := new ClassB();
|
||||
obj := findClass("ClassA", objb);
|
||||
writeLn(obj.Fuc());
|
||||
writeLn(obj.Func());
|
||||
|
||||
type ClassA = class
|
||||
public
|
||||
function Fuc(); virtual;
|
||||
function Func(); virtual;
|
||||
begin
|
||||
return "ClassA";
|
||||
end;
|
||||
end;
|
||||
type ClassB = class(ClassA)
|
||||
public
|
||||
function Fuc(); override;
|
||||
function Func(); override;
|
||||
begin
|
||||
return "ClassB";
|
||||
end;
|
||||
@@ -183,10 +183,10 @@ end;
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
oa := new ca("abc");
|
||||
oa := new Ca("abc");
|
||||
writeLn(objectstate(oa));
|
||||
|
||||
type ca = class
|
||||
type Ca = class
|
||||
public
|
||||
static sca;
|
||||
function create(n);
|
||||
@@ -208,20 +208,20 @@ end;
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
o := new ca();
|
||||
o := new Ca();
|
||||
o.c := 3;
|
||||
writeLn(o.c);
|
||||
|
||||
type ca = class
|
||||
type Ca = class
|
||||
public
|
||||
value;
|
||||
property c read getc write setc;
|
||||
function setc(v);
|
||||
property c read Getc write Setc;
|
||||
function Setc(v);
|
||||
begin
|
||||
writeLn(tslassigning);
|
||||
value := v;
|
||||
end;
|
||||
function getc();
|
||||
function Getc();
|
||||
begin
|
||||
writeLn(tslassigning);
|
||||
return value;
|
||||
@@ -302,16 +302,16 @@ end;
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
t := findOverLoad(2, "fun", new TestClass());
|
||||
t := findOverLoad(2, "Fun", new TestClass());
|
||||
writeLn(t.do(1, 2));
|
||||
|
||||
type TestClass = class
|
||||
public
|
||||
function fun(p1, p2); overload;
|
||||
function Fun(p1, p2); overload;
|
||||
begin
|
||||
return p1 + p2;
|
||||
end;
|
||||
function fun(p1); overload;
|
||||
function Fun(p1); overload;
|
||||
begin
|
||||
return p1 + 10;
|
||||
end;
|
||||
@@ -321,7 +321,7 @@ end;
|
||||
结果说明:
|
||||
|
||||
- 输出 `3`
|
||||
- 说明 `findOverLoad(2, "fun", obj)` 可以按参数个数拿到对应重载方法
|
||||
- 说明 `findOverLoad(2, "Fun", obj)` 可以按参数个数拿到对应重载方法
|
||||
|
||||
### 函数信息、对象枚举与生命周期
|
||||
|
||||
@@ -356,14 +356,15 @@ end;
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
objA := new TestClass01(100);
|
||||
objB := new TestClass01(101);
|
||||
objsInfo := tslObjects(1);
|
||||
writeLn(length(objsInfo["TestClass01"]));
|
||||
newObjA := objsInfo["TestClass01"][0, "obj"];
|
||||
writeLn(newObjA is class(TestClass01));
|
||||
writeLn(newObjA.add(1, 2));
|
||||
|
||||
objA := new TestClass01(100);
|
||||
objB := new TestClass01(101);
|
||||
|
||||
type TestClass01 = class
|
||||
public
|
||||
value;
|
||||
@@ -371,7 +372,7 @@ public
|
||||
begin
|
||||
value := _value;
|
||||
end;
|
||||
class function add(x, y);
|
||||
class function Add(x, y);
|
||||
begin
|
||||
return x + y;
|
||||
end;
|
||||
@@ -556,7 +557,7 @@ end;
|
||||
- 不要把 `objectstate(self)` 里的 `self` 泛化成普通成员访问都要加 `self` 前缀。
|
||||
- 不要把弱引用能力的条件编译宏写成 `weakRef`。
|
||||
- 不要以为 `weakref_get(deadWeakRef)` 会像普通可空访问那样安全返回 `nil`。
|
||||
- 不要以为类内段落式 `weakRef;` / `autoRef;` 也能直接通过。
|
||||
- 不要给段落切换关键字加分号;`weakRef;` / `autoRef;`(带分号)会报 `invalid class definition`,段落式要写成不带分号的 `weakRef` / `autoRef`。
|
||||
- 不要以为 `[weakRef]` 成员会继续强持有对象。
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
@@ -573,4 +574,33 @@ public
|
||||
end;
|
||||
```
|
||||
|
||||
上面这种把 `weakRef;` / `autoRef;` 当作类内段落切换的写法不作为可写事实,会编译失败,错误信息包含 `invalid class definition`。
|
||||
上面这种给段落切换关键字**加分号**(`weakRef;` / `autoRef;`)的写法会编译失败,错误信息包含 `invalid class definition`。关键在分号:段落切换关键字要像 `public` / `private` 那样**不带分号**独占一行,带分号后被当成独立语句才报错。正确的段落式写法见下一段。
|
||||
|
||||
段落式 `weakRef` / `autoRef`(不带分号)像 `public` / `private` 一样切换后续成员的弱引用属性:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
o := new AutoWeakTest();
|
||||
o.fa := 1;
|
||||
o.fb := 2;
|
||||
writeLn(o.fa, ',', o.fb);
|
||||
|
||||
type AutoWeakTest = class
|
||||
public
|
||||
fa;
|
||||
weakRef
|
||||
fOnClick;
|
||||
fOnDblClick;
|
||||
autoRef
|
||||
fb;
|
||||
end;
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- 输出 `1,2`
|
||||
- `weakRef`(不带分号)打开后续成员的自动弱引用开关,`fOnClick` / `fOnDblClick` 成为弱引用成员
|
||||
- `autoRef`(不带分号)关闭开关,`fb` 恢复为强引用成员
|
||||
- 段落切换只影响其后、下一个切换关键字之前的成员;`fa` 在初始(强引用)段
|
||||
- 这与行内 `[weakRef] field;` 是两种可用写法:行内只作用于单个成员,段落式作用于整段
|
||||
|
||||
@@ -46,13 +46,13 @@
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
obj := new TStringList();
|
||||
obj.CommaText := "A=aaa,B=bbb,C=222";
|
||||
writeLn(obj[1]);
|
||||
writeLn(obj["B"]);
|
||||
writeLn(obj.Count);
|
||||
obj.Add("D=444");
|
||||
writeLn(obj.Count);
|
||||
list := new TStringList();
|
||||
list.CommaText := "A=aaa,B=bbb,C=222";
|
||||
writeLn(list[1]);
|
||||
writeLn(list["B"]);
|
||||
writeLn(list.Count);
|
||||
list.Add("D=444");
|
||||
writeLn(list.Count);
|
||||
```
|
||||
|
||||
结果说明:
|
||||
@@ -65,11 +65,11 @@ writeLn(obj.Count);
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
obj := new THashedStringList();
|
||||
obj.Add("A=aaa");
|
||||
obj.Add("B=bbb");
|
||||
writeLn(obj.Count);
|
||||
writeLn(obj["B"]);
|
||||
list := new THashedStringList();
|
||||
list.Add("A=aaa");
|
||||
list.Add("B=bbb");
|
||||
writeLn(list.Count);
|
||||
writeLn(list["B"]);
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
是否含不可照写反例:是
|
||||
遇到不确定时:先按本页候选页继续判断;[12_matrix_and_collections.md](12_matrix_and_collections.md)、[23_fmarray.md](23_fmarray.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md)
|
||||
|
||||
这一篇只讲矩阵专用语法主干:矩阵初始化、数列构造、矩阵逆/广义逆、矩阵尺寸与索引、矩阵遍历、子矩阵和 `mfind` 查找。它和 [12_matrix_and_collections.md](12_matrix_and_collections.md) 的分工是:`12` 讲普通数组与集合关系,这一篇讲矩阵专用构造、遍历、子矩阵和矩阵查找接口。
|
||||
这一篇只讲矩阵专用语法主干:矩阵初始化、数列构造、矩阵逆/广义逆、矩阵乘除乘方、矩阵转置、矩阵拼接、矩阵尺寸与索引、矩阵遍历、子矩阵和 `mfind` 查找。它和 [12_matrix_and_collections.md](12_matrix_and_collections.md) 的分工是:`12` 讲普通数组与集合关系,这一篇讲矩阵专用构造、运算、遍历、子矩阵和矩阵查找接口。
|
||||
|
||||
## 本篇职责
|
||||
|
||||
回答“怎样直接构造全零矩阵、全一矩阵、随机矩阵、单位矩阵、空矩阵和数列数组,怎样写矩阵逆/广义逆,怎样拿到矩阵的行数、列数、行索引和列索引,怎样遍历矩阵、取/改子矩阵,以及怎样用 `mfind` 找到或替换符合条件的单元格”。
|
||||
回答”怎样直接构造全零矩阵、全一矩阵、随机矩阵、单位矩阵、空矩阵和数列数组,怎样写矩阵逆/广义逆,怎样进行矩阵乘除乘方,怎样转置矩阵,怎样拼接矩阵,怎样拿到矩阵的行数、列数、行索引和列索引,怎样遍历矩阵、取/改子矩阵,以及怎样用 `mfind` 找到或替换符合条件的单元格”。
|
||||
|
||||
## 智能体矩阵深水判断流程
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
## 核心规则
|
||||
|
||||
- 矩阵初始化函数的参数规格见 [../reference/catalog/math.md](../reference/catalog/math.md);本页只保留矩阵行为示例和返回形态边界。
|
||||
- 矩阵初始化函数的参数规格见 [../codegen/builtin/math.md](../codegen/builtin/math.md);本页只保留矩阵行为示例和返回形态边界。
|
||||
- `zeros(...)`、`ones(...)`、`rand(...)`、`nils(...)`、`eye(...)` 都可以直接用于矩阵初始化。
|
||||
- `zeros(3)`、`ones(3)`、`nils(2)` 这类单参数写法可以直接生成一维结果。
|
||||
- `zeros(2, 3)`、`rand(2, 3)` 这类双参数写法可以直接生成二维矩阵。
|
||||
@@ -34,7 +34,7 @@
|
||||
- `eye(3)` 生成的是 `3 x 3` 单位矩阵,不是一维数组。
|
||||
- `->` 用来生成数列;默认步长是 `1`,也可以显式传入步长和索引数组。
|
||||
- 在矩阵语境里,`!A` 是一元倒数运算符作用于矩阵的形态,用于矩阵逆/广义逆;非方阵输入可以返回行列数互换后的广义逆结果。
|
||||
- `msize(...)`、`mrows(...)`、`mcols(...)` 的参数规格见 [../reference/catalog/system.md](../reference/catalog/system.md)。
|
||||
- `msize(...)`、`mrows(...)`、`mcols(...)` 的参数规格见 [../codegen/special/pending/system/01_data_type.md](../codegen/special/pending/system/01_data_type.md)。
|
||||
- `msize(matrix_value)` 返回 `array(行数, 列数)`。
|
||||
- `msize(matrix_value, 1)` 返回行索引数组和列索引数组。
|
||||
- `mrows(matrix_value)` / `mcols(matrix_value)` 默认返回数量;第二个参数写成 `1` 时返回索引数组。
|
||||
@@ -527,6 +527,380 @@ B
|
||||
0
|
||||
```
|
||||
|
||||
### 矩阵乘法、除法、乘方:`:*`、`:/`、`:^`
|
||||
|
||||
`:*` 是矩阵乘法(区别于逐元素乘 `*`):
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array((1, 2), (3, 4));
|
||||
b := array((5, 6), (7, 8));
|
||||
element_wise := a * b;
|
||||
matrix_multiply := a :* b;
|
||||
writeLn("逐元素乘 (0,0):", element_wise[0][0]);
|
||||
writeLn("矩阵乘 (0,0):", matrix_multiply[0][0]);
|
||||
writeLn("矩阵乘 (0,1):", matrix_multiply[0][1]);
|
||||
writeLn("矩阵乘 (1,0):", matrix_multiply[1][0]);
|
||||
writeLn("矩阵乘 (1,1):", matrix_multiply[1][1]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
逐元素乘 (0,0): 5
|
||||
矩阵乘 (0,0): 19
|
||||
矩阵乘 (0,1): 22
|
||||
矩阵乘 (1,0): 43
|
||||
矩阵乘 (1,1): 50
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `*` 是逐元素乘(element-wise),`a * b` 的 `(0,0)` 是 `1 * 5 = 5`
|
||||
- `:*` 是真正的矩阵乘法,`a :* b` 的 `(0,0)` 是 `1*5 + 2*7 = 19`
|
||||
- 矩阵乘法要求左矩阵列数等于右矩阵行数
|
||||
|
||||
`:/` 是矩阵除法(等价于 `A :* !B`):
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array((1, 2), (3, 4));
|
||||
b := array((2, 0), (0, 2));
|
||||
result := a :/ b;
|
||||
writeLn(result[0][0]);
|
||||
writeLn(result[0][1]);
|
||||
writeLn(result[1][0]);
|
||||
writeLn(result[1][1]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
0.5
|
||||
1
|
||||
1.5
|
||||
2
|
||||
```
|
||||
|
||||
`:\` 是矩阵左除(等价于 `!A :* B`,常用于解线性方程组):
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array((2, 0), (0, 4));
|
||||
b := array((4), (8));
|
||||
result := a :\ b;
|
||||
writeLn(result[0][0]);
|
||||
writeLn(result[1][0]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
2
|
||||
2
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `:\` 左除用于解线性方程组 `A * X = B`,等价于 `X = A^(-1) * B`
|
||||
- **右侧 `b` 必须是列向量**(用 `array((4), (8))` 而非 `array(4, 8)`)
|
||||
- `a :\ b` 返回 `array((2.0), (2.0))`,即 `X` 的列向量
|
||||
- 当 A 行数 > 列数时返回最小二乘解,行数 < 列数时返回一个可行解
|
||||
|
||||
`:^` 是矩阵乘方(`A :^ 2` 等价于 `A :* A`):
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array((1, 1), (0, 1));
|
||||
pow2 := a :^ 2;
|
||||
manual := a :* a;
|
||||
writeLn("pow (0,0):", pow2[0][0]);
|
||||
writeLn("pow (0,1):", pow2[0][1]);
|
||||
writeLn("pow (1,1):", pow2[1][1]);
|
||||
writeLn("manual (0,1):", manual[0][1]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
pow (0,0): 1
|
||||
pow (0,1): 2
|
||||
pow (1,1): 1
|
||||
manual (0,1): 2
|
||||
```
|
||||
|
||||
复合赋值算符:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array((1, 2), (3, 4));
|
||||
b := array((1, 0), (0, 1));
|
||||
a :*= b;
|
||||
writeLn(a[0][0]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
1
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `:*=`、`:/=`、`:\=`、`:^=` 分别是矩阵乘、除、左除、乘方的复合赋值形式
|
||||
- `a :*= b` 等价于 `a := a :* b`
|
||||
|
||||
### 基础函数的矩阵广播与异常处理参数
|
||||
|
||||
多参数基础函数支持逐参数广播:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
data := array(1.55, 2.99, 3.85);
|
||||
precision := array(-1, 0, 0);
|
||||
result := RoundTo(data, precision);
|
||||
writeLn(result[0]);
|
||||
writeLn(result[1]);
|
||||
writeLn(result[2]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
1.6
|
||||
3
|
||||
4
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `RoundTo(data, precision)` 对两个数组逐元素配对:`RoundTo(1.55, -1)` → `1.6`、`RoundTo(2.99, 0)` → `3.0`
|
||||
- 规则:为每个参数寻找一个或一组匹配者,逐参数广播
|
||||
|
||||
基础函数尾部可追加异常处理参数 `ErrDefine` 和 `ErrReplace`:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
data := array(4, -1, 9);
|
||||
result := sqrt(data, 1, -999);
|
||||
writeLn(tostn(result));
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
array(2.0,NAN,3.0)
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `sqrt(data, 1, -999)` 中,第二参数 `ErrDefine=1` 表示允许 NIL 值不允许错误值
|
||||
- `ErrReplace=-999` 是错误位置的替换值(本例中 `-1` 的平方根为错误,但 `ErrDefine=1` 保留为 NAN)
|
||||
- `ErrDefine` 取值:`0`=不允许错误和 NIL、`1`=允许 NIL 不允许错误、`2`=错误值保留为原值
|
||||
- `ErrReplace` 在 `ErrDefine=0` 或 `1` 时生效,用于替换错误/NIL 位置
|
||||
|
||||
另一个例子:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
data := array(1, nil, "AAA", -100);
|
||||
result := abs(data, 0, -999);
|
||||
writeLn(tostn(result));
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
array(1,-999,-999,100)
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `abs(data, 0, -999)` 中,`ErrDefine=0` 不允许错误和 NIL
|
||||
- `nil` 和 `"AAA"` 都被替换成 `-999`
|
||||
- 对于多参数基础函数,`ErrDefine` 和 `ErrReplace` 总是可以作为可选参数添加在最后
|
||||
|
||||
### 矩阵转置:反引号 `` ` ``
|
||||
|
||||
单次转置交换行列:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array((1, 2, 3), (4, 5, 6));
|
||||
transposed := `a;
|
||||
writeLn("原矩阵行数:", mrows(a));
|
||||
writeLn("原矩阵列数:", mcols(a));
|
||||
writeLn("转置后行数:", mrows(transposed));
|
||||
writeLn("转置后列数:", mcols(transposed));
|
||||
writeLn("转置 (0,0):", transposed[0][0]);
|
||||
writeLn("转置 (1,0):", transposed[1][0]);
|
||||
writeLn("转置 (2,0):", transposed[2][0]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
原矩阵行数: 2
|
||||
原矩阵列数: 3
|
||||
转置后行数: 3
|
||||
转置后列数: 2
|
||||
转置 (0,0): 1
|
||||
转置 (1,0): 2
|
||||
转置 (2,0): 3
|
||||
```
|
||||
|
||||
一维数组转置成列向量:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
b := array(1, 2, 3);
|
||||
col_vector := `b;
|
||||
writeLn("一维长度:", length(b));
|
||||
writeLn("列向量行数:", mrows(col_vector));
|
||||
writeLn("列向量列数:", mcols(col_vector));
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
一维长度: 3
|
||||
列向量行数: 3
|
||||
列向量列数: 1
|
||||
```
|
||||
|
||||
双转置把一维数组变成行向量(常用于 `union` 追加行):
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
b := array(1, 2, 3);
|
||||
row_vector := ``b;
|
||||
writeLn("行向量行数:", mrows(row_vector));
|
||||
writeLn("行向量列数:", mcols(row_vector));
|
||||
writeLn("行向量 (0,0):", row_vector[0][0]);
|
||||
writeLn("行向量 (0,1):", row_vector[0][1]);
|
||||
writeLn("行向量 (0,2):", row_vector[0][2]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
行向量行数: 1
|
||||
行向量列数: 3
|
||||
行向量 (0,0): 1
|
||||
行向量 (0,1): 2
|
||||
行向量 (0,2): 3
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `` `a `` 是后缀算符,写在矩阵变量或表达式之后
|
||||
- 一维数组 `b` 转置一次成列向量(3行1列),转置两次成行向量(1行3列)
|
||||
- 双转置技巧常配合 `union` 逐行追加数据
|
||||
|
||||
### 矩阵拼接:`union`、`&=`、`|`、`:|`
|
||||
|
||||
`union` 按行拼接(一维或二维):
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array(1, 2, 3);
|
||||
b := array(4, 5, 6);
|
||||
result := a union b;
|
||||
writeLn(length(result));
|
||||
writeLn(result[0]);
|
||||
writeLn(result[3]);
|
||||
writeLn(result[5]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
6
|
||||
1
|
||||
4
|
||||
6
|
||||
```
|
||||
|
||||
`&=` 是 `union` 的复合赋值形式(注意不是 `union=`):
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array(1, 2, 3);
|
||||
b := array(4, 5, 6);
|
||||
a &= b;
|
||||
writeLn(length(a));
|
||||
writeLn(a[5]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
6
|
||||
6
|
||||
```
|
||||
|
||||
`|` 按列拼接:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array((1, 2), (3, 4));
|
||||
b := array((5, 6), (7, 8));
|
||||
result := a | b;
|
||||
writeLn("列数:", mcols(result));
|
||||
writeLn("(0,2):", result[0][2]);
|
||||
writeLn("(1,3):", result[1][3]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
列数: 4
|
||||
(0,2): 5
|
||||
(1,3): 8
|
||||
```
|
||||
|
||||
`:|` 对非完全矩阵补 `nil`,`|` 不补:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := array((1, 2, 3), (2, 3));
|
||||
colon_result := a :| a;
|
||||
bar_result := a | a;
|
||||
writeLn("colon 结果列数:", mcols(colon_result));
|
||||
writeLn("colon (1,2):", colon_result[1][2]);
|
||||
writeLn("bar 结果 (1,2):", bar_result[1][2]);
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
colon 结果列数: 6
|
||||
colon (1,2): nil
|
||||
bar 结果 (1,2): 1
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `union` / `&=` 用于行方向拼接
|
||||
- `|` / `:|` 用于列方向拼接
|
||||
- 非完全矩阵(行长度不一致)用 `:|` 会在缺位补 `nil`,而 `|` 不补
|
||||
- 对应的复合赋值形式:`&=`(行并)、`|=`(列并)、`:|=`(列并补 nil)
|
||||
|
||||
## 默认生成模板
|
||||
|
||||
需要矩阵构造时,优先从这个最短模板开始:
|
||||
@@ -541,12 +915,18 @@ matrix_value := zeros(2, 3);
|
||||
|
||||
- 把 `eye(3)` 当成一维数组。
|
||||
- 把 `!A` 当成逻辑非表达式。
|
||||
- 把 `*` 当成矩阵乘法;矩阵乘法使用 `:*`。
|
||||
- 把 `:*`、`:/`、`:\`、`:^` 当成逐元素运算;逐元素运算使用 `*`、`/`、`^`。
|
||||
- 在 `:\` 左除时,右侧用一维数组而非列向量;右侧必须用 `array((v1), (v2), ...)` 形式。
|
||||
- 以为 `mrows(matrix_value, 1)` 和 `mcols(matrix_value, 1)` 返回的还是数量。
|
||||
- 写带步长的 `->` 时,漏掉外层 `array(...)`。
|
||||
- 还在普通数组页里硬塞矩阵专用大小接口。
|
||||
- 把 `::=` 写成带 `begin ... end` 的语句块。
|
||||
- 用 `::` 期待遍历到任意深度;深度遍历使用 `:.`。
|
||||
- 子矩阵赋值时用形状不匹配的矩阵硬塞。
|
||||
- 把 `union` 的复合赋值写成 `union=`;正确写法是 `&=`。
|
||||
- 一维数组直接 `union` 期待得到二维结果;需要先双转置 `` ``b `` 变成行向量。
|
||||
- 在基础函数异常参数时用分号分隔;正确写法用逗号:`sqrt(data, 1, -999)`。
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
- `fmarray[...]` 可以直接构造 `FMArray` 常量。
|
||||
- `dataType(v)` 对 `FMArray` 返回 `27`。
|
||||
- `dataType(v, 1)` 可以读出 `FMArray` 单元格类型;本页文档类型包括 `0` 整型、`1` 浮点、`20` 64 位整型。
|
||||
- FMArray 相关函数的参数规格见 [../reference/catalog/system.md](../reference/catalog/system.md) 和 [../reference/catalog/math.md](../reference/catalog/math.md);本页只保留 FMArray 行为示例和返回形态边界。
|
||||
- FMArray 相关函数的参数规格见 [../codegen/special/pending/system/01_data_type.md](../codegen/special/pending/system/01_data_type.md) 和 [../codegen/builtin/math.md](../codegen/builtin/math.md);本页只保留 FMArray 行为示例和返回形态边界。
|
||||
- `ifFmarray(v)` 可直接判断值是否为 `FMArray`。
|
||||
- `mInit`、`mInitDiag`、`mRand` 都可直接生成 `FMArray`。
|
||||
- `arrayToFm` 和 `matrixToArray` 可在 `Array` / `FMArray` 间互转。
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
|
||||
## 核心规则
|
||||
|
||||
- 对象二元算符重载的最小可靠形态是成员方法 `function operator + (data);` 这一类写法。
|
||||
- 比较算符可写成 `function operator < (data, isLeft);`,用 `isLeft` 区分对象在左边还是右边。
|
||||
- 对象二元算符重载的最小可靠形态是成员方法 `function operator + (other);` 这一类写法。
|
||||
- 比较算符可写成 `function operator < (other, is_left);`,用 `is_left` 区分对象在左边还是右边。
|
||||
- 对象 `[]` 读取有两种文档明确写法:`function operator[](index);` 和 `function operator[0](index, s1);`。
|
||||
- 对象 `[]` 写入的文档明确写法是 `function operator[1](index, v);`。
|
||||
- `function operator for(flag);` 可以重载 `for in`。
|
||||
@@ -31,7 +31,7 @@
|
||||
- `mrows` / `mcols` / `msize` 可以在类里先声明 `function operator mrows(n);` 这类签名,再在类外实现 `function operator ClassName.mrows(n);`。
|
||||
- 可用形态包括 `mrows(obj)`、`mcols(obj)`、`msize(obj)` 这类关键字调用,以及 `obj.mcols(1)` 这类对象方法式调用。
|
||||
- `function operator++(v);` 和 `function operator += (v);` 也可用。
|
||||
- 不要把未写入文档资料里的裸 `function operator;` / `function operator1;`,或未列入本页的 `mcell` / `mrow` / `mcol` / `::` / `:.` 重载,直接当成语法事实。
|
||||
- 不要把未写入文档资料里的裸 `function operator;` / `function operator1;` 直接当成语法事实。`::` / `:.` / `mcell` / `mrow` / `mcol` / `mIndexCount` / `mIndex` 的重载本页已给出可照写形态,照本页示例写即可。
|
||||
|
||||
## 可直接照写示例
|
||||
|
||||
@@ -40,46 +40,49 @@
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
t1 := new TComplex();
|
||||
t1.vReal := 10;
|
||||
t1.vImaginary := 100;
|
||||
t2 := t1 + 10;
|
||||
writeLn(t2.vReal);
|
||||
writeLn(t1 < 5);
|
||||
writeLn(t1 < 300);
|
||||
writeLn(5 < t1);
|
||||
c1 := new Complex();
|
||||
c1.RealPart := 10;
|
||||
c1.ImaginaryPart := 100;
|
||||
c2 := c1 + 10;
|
||||
writeLn(c2.RealPart);
|
||||
writeLn(c1 < 5);
|
||||
writeLn(c1 < 300);
|
||||
writeLn(5 < c1);
|
||||
|
||||
type TComplex = class
|
||||
type Complex = class
|
||||
public
|
||||
vReal;
|
||||
vImaginary;
|
||||
function operator + (data);
|
||||
property RealPart read real_part_ write real_part_;
|
||||
property ImaginaryPart read imaginary_part_ write imaginary_part_;
|
||||
function operator + (other);
|
||||
begin
|
||||
r := new TComplex();
|
||||
if ifNumber(data) then
|
||||
sum := new Complex();
|
||||
if ifNumber(other) then
|
||||
begin
|
||||
r.vReal := vReal + data;
|
||||
sum.RealPart := real_part_ + other;
|
||||
end
|
||||
else
|
||||
begin
|
||||
r.vReal := vReal + data.vReal;
|
||||
r.vImaginary := vImaginary + data.vImaginary;
|
||||
sum.RealPart := real_part_ + other.RealPart;
|
||||
sum.ImaginaryPart := imaginary_part_ + other.ImaginaryPart;
|
||||
end
|
||||
return r;
|
||||
return sum;
|
||||
end;
|
||||
function operator < (data, isLeft);
|
||||
function operator < (other, is_left);
|
||||
begin
|
||||
if ifNumber(data) then
|
||||
if ifNumber(other) then
|
||||
begin
|
||||
v := vReal < data;
|
||||
less := real_part_ < other;
|
||||
end
|
||||
else
|
||||
begin
|
||||
v := (vReal ^ 2 + vImaginary ^ 2) < data.vReal ^ 2 + data.vImaginary ^ 2;
|
||||
less := (real_part_ ^ 2 + imaginary_part_ ^ 2) < other.RealPart ^ 2 + other.ImaginaryPart ^ 2;
|
||||
end
|
||||
if not isLeft then v := not v;
|
||||
return v;
|
||||
if not is_left then less := not less;
|
||||
return less;
|
||||
end;
|
||||
private
|
||||
real_part_;
|
||||
imaginary_part_;
|
||||
end;
|
||||
```
|
||||
|
||||
@@ -87,7 +90,8 @@ end;
|
||||
|
||||
- 依次输出 `20`、`0`、`1`、`1`
|
||||
- 说明 `obj + value` 可以通过成员 `operator +` 接管
|
||||
- 说明带 `isLeft` 的比较算符可以同时处理 `obj < value` 和 `value < obj`
|
||||
- 说明带 `is_left` 的比较算符可以同时处理 `obj < value` 和 `value < obj`
|
||||
- 私有成员用尾随下划线的 `real_part_` / `imaginary_part_`,对外用 `PascalCase` property 暴露
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
@@ -104,12 +108,12 @@ end;
|
||||
|
||||
```tsl
|
||||
t := array(1, 2, 3, 4, 5);
|
||||
b := new bb(t);
|
||||
b := new IndexableBox(t);
|
||||
writeLn(b[2]);
|
||||
b[3] := 999;
|
||||
writeLn(b.data[3]);
|
||||
|
||||
type bb = class
|
||||
type IndexableBox = class
|
||||
public
|
||||
data;
|
||||
function create(v);
|
||||
@@ -139,7 +143,7 @@ end;
|
||||
代码块身份:配置片段 / 概念骨架
|
||||
|
||||
```tsl
|
||||
type bb = class
|
||||
type IndexableBox = class
|
||||
public
|
||||
// 其余字段、create()、operator[1] 和测试主体同上一段
|
||||
function operator[0](index, s1);
|
||||
@@ -265,16 +269,16 @@ end;
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
b := new bb(10);
|
||||
++b;
|
||||
writeLn(b.data);
|
||||
c := b++;
|
||||
counter := new Counter(10);
|
||||
++counter;
|
||||
writeLn(counter.data);
|
||||
c := counter++;
|
||||
writeLn(c.data);
|
||||
writeLn(b.data);
|
||||
b += 5;
|
||||
writeLn(b.data);
|
||||
writeLn(counter.data);
|
||||
counter += 5;
|
||||
writeLn(counter.data);
|
||||
|
||||
type bb = class
|
||||
type Counter = class
|
||||
public
|
||||
data;
|
||||
function create(v);
|
||||
@@ -285,7 +289,7 @@ public
|
||||
begin
|
||||
if v = 0 then
|
||||
begin
|
||||
r := new bb();
|
||||
r := new Counter();
|
||||
r.data := data;
|
||||
r.data++;
|
||||
return r;
|
||||
@@ -304,22 +308,250 @@ end;
|
||||
|
||||
- 依次输出 `11`、`11`、`12`、`17`
|
||||
- 说明前置 `++` 会直接修改对象状态
|
||||
- 说明这个最小样例里,后置 `b++` 返回的是递增前快照
|
||||
- 说明 `operator += (v)` 可以接管 `b += 5`
|
||||
- 说明这个最小样例里,后置 `counter++` 返回的是递增前快照
|
||||
- 说明 `operator += (v)` 可以接管 `counter += 5`
|
||||
|
||||
`--` 与 `-=` 与之对称:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
counter := new Counter(10);
|
||||
counter -= 3;
|
||||
writeLn(counter.data);
|
||||
|
||||
type Counter = class
|
||||
public
|
||||
data;
|
||||
function create(v);
|
||||
begin
|
||||
data := v;
|
||||
end;
|
||||
function operator--(v);
|
||||
begin
|
||||
if v = 0 then
|
||||
begin
|
||||
r := new Counter();
|
||||
r.data := data;
|
||||
r.data--;
|
||||
return r;
|
||||
end
|
||||
else
|
||||
data--;
|
||||
end;
|
||||
function operator -= (v);
|
||||
begin
|
||||
data -= v;
|
||||
end;
|
||||
end;
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- 输出 `7`
|
||||
- 说明 `operator -= (v)` 可以接管 `counter -= 3`
|
||||
- `operator--(v)` 与 `operator++(v)` 结构对称:`v = 0` 分支返回递减前快照,否则原地递减
|
||||
|
||||
### 二进制函数重载:`operator funcName`
|
||||
|
||||
除了符号算符,`operator` 还能重载具名的全局二进制函数(如 `DateToStr`、`TryStrToInt` 等)。定义写成 `[class] function operator funcName(...)`:`class` 关键字可选,加上表示类方法,不加表示成员函数。
|
||||
|
||||
成员函数重载(参数比原函数少 1 个,用第一个参数的对象实例调用):
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
d := new IntDate(20240329);
|
||||
writeLn(DateToStr(d));
|
||||
|
||||
type IntDate = class
|
||||
public
|
||||
value;
|
||||
function create(v);
|
||||
begin
|
||||
value := v;
|
||||
end;
|
||||
function operator DateToStr();
|
||||
begin
|
||||
v := IntToDate(value);
|
||||
return DateToStr(v);
|
||||
end;
|
||||
end;
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- 输出 `2024-03-29`
|
||||
- 说明 `DateToStr(d)` 被对象的成员 `operator DateToStr` 接管
|
||||
- 成员函数重载时参数个数比原二进制函数少 1 个,第一个实参(对象本身)用于定位方法
|
||||
|
||||
类方法重载(`class function`,参数与原函数一致):
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
d := new IntDate2(20240329);
|
||||
writeLn(DateToStr(d));
|
||||
|
||||
type IntDate2 = class
|
||||
public
|
||||
value;
|
||||
function create(v);
|
||||
begin
|
||||
value := v;
|
||||
end;
|
||||
class function operator DateToStr(t);
|
||||
begin
|
||||
t := ifObj(t) ? t.value : t;
|
||||
return DateToStr(IntToDate(t));
|
||||
end;
|
||||
end;
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- 输出 `2024-03-29`
|
||||
- 说明 `class function operator DateToStr(t)` 作为类方法接管调用,参数个数与原二进制函数一致
|
||||
|
||||
类内用 `::` 调同名全局函数(避免重载递归):
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
c := new ClassA();
|
||||
c.value := "314";
|
||||
ret := TryStrToInt(c, msg);
|
||||
writeLn(tostn(array(ret, msg)));
|
||||
|
||||
type ClassA = class
|
||||
public
|
||||
value;
|
||||
function operator TryStrToInt(msg);
|
||||
begin
|
||||
return ::TryStrToInt(value, msg);
|
||||
end;
|
||||
end;
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- 输出 `array(1,314)`:`ret` 为 `1`(转换成功),出参 `msg` 为 `314`
|
||||
- 说明类内需要调用被重载的同名全局函数时,用 `::` 前缀指定全局版本,否则会递归回自己
|
||||
- 重载函数支持通过参数传出返回值(`msg` 作为出参被赋值)
|
||||
|
||||
### `::` / `:.` 遍历重载与 `mcell` / `mrow` / `mcol` / `mIndexCount` / `mIndex`
|
||||
|
||||
重载 `::`(二维遍历)或 `:.`(深度遍历)后,对象就能像矩阵一样被 `obj::begin ... end` 遍历。遍历体里用到的 `mcell` / `mrow` / `mcol` / `mIndexCount` / `mIndex(n)` 也各自重载,返回当前单元的值、行下标、列下标、维度数和第 `n` 维下标。`operator ::(flag)` 的 `flag` 为 `0` 表示第一次循环、`1` 表示后续循环,返回 `0` 或 `nil` 结束遍历、返回非零数字继续:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
t := array("A": 0 -> 3, "B": 10 -> 2, "C": 20 -> 21);
|
||||
traversable := new TraversableMatrix(t);
|
||||
traversable::begin
|
||||
echo "mcell:", mcell, " mrow:", mrow, " mcol:", mcol, " mIndexCount:", mIndexCount, "\r\n";
|
||||
end
|
||||
|
||||
type TraversableMatrix = class
|
||||
public
|
||||
data;
|
||||
Rdata;
|
||||
findex;
|
||||
lengtD;
|
||||
function create(v);
|
||||
begin
|
||||
data := v;
|
||||
end;
|
||||
function operator ::(flag);
|
||||
begin
|
||||
if not flag then
|
||||
begin
|
||||
Rdata := array();
|
||||
k := 0;
|
||||
data::begin
|
||||
Rdata[k] := array(mcell, mIndexCount, mrow, mcol);
|
||||
if mIndexCount > 2 then for i := 2 to mIndexCount - 1 do Rdata[k, i + 2] := mIndex(i);
|
||||
k++;
|
||||
end
|
||||
lengtD := length(Rdata);
|
||||
findex := 0;
|
||||
end
|
||||
else if findex < lengtD - 1 then findex++;
|
||||
else return nil;
|
||||
return 1;
|
||||
end;
|
||||
function operator mcell();
|
||||
begin
|
||||
return Rdata[findex][0];
|
||||
end;
|
||||
function operator mIndexCount();
|
||||
begin
|
||||
return Rdata[findex][1];
|
||||
end;
|
||||
function operator mrow();
|
||||
begin
|
||||
return Rdata[findex][2];
|
||||
end;
|
||||
function operator mcol();
|
||||
begin
|
||||
return Rdata[findex][3];
|
||||
end;
|
||||
function operator mIndex(n);
|
||||
begin
|
||||
if n < Rdata[findex][1] then
|
||||
return Rdata[findex][n + 2];
|
||||
else raise "指定的维度超出最大维度数";
|
||||
end;
|
||||
end;
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- 逐行输出每个单元的 `mcell` / `mrow` / `mcol` / `mIndexCount`,遍历顺序与被代理的 `data` 一致
|
||||
- `operator ::(flag)` 里 `flag=0` 时初始化把 `data` 的遍历结果缓存进 `Rdata`,之后每次推进 `findex`
|
||||
- 返回 `1` 表示继续、返回 `nil` 表示结束
|
||||
- `:.`(深度遍历)重载方式与 `::` 相同,把内部 `data::begin ... end` 换成 `data:.begin ... end` 即可
|
||||
- 遍历体里用到的 `mcell` / `mrow` / `mcol` / `mIndexCount` / `mIndex` 必须各自重载,否则报 `override function not found`
|
||||
|
||||
### 关键字函数重载:`msize` / `mrows` / `mcols`
|
||||
|
||||
`msize` / `mrows` / `mcols` 这类关键字函数也能重载,形态同二进制函数重载 `[class] function operator KeyWord(...)`,但**关键字重载不需要 `::` 指定全局**:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
grid := new GridData();
|
||||
writeLn(mcols(grid));
|
||||
|
||||
type GridData = class
|
||||
public
|
||||
fa;
|
||||
function create();
|
||||
begin
|
||||
fa := array(("A": 1, "B": 2, "C": 3), ("A": 5, "B": 5, "C": 5));
|
||||
end;
|
||||
function operator mcols();
|
||||
begin
|
||||
return mcols(fa);
|
||||
end;
|
||||
end;
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- 输出 `3`:`mcols(grid)` 被对象的 `operator mcols()` 接管,返回内部 `fa` 的列数
|
||||
- 关键字函数重载与二进制函数重载写法一致,但类内调用同名关键字函数不需要 `::` 前缀
|
||||
|
||||
## 本页不生成的范围
|
||||
|
||||
- `::` / `:.` 遍历重载
|
||||
- `mcell` / `mrow` / `mcol` / `mIndexCount` / `mIndex`
|
||||
- 多级 `[]` 下标重载
|
||||
- 右侧算术如 `value + obj`
|
||||
- 对基础二进制函数的大规模重载族
|
||||
|
||||
这些名称只作为边界提示,不作为本页可生成模板。
|
||||
|
||||
## 禁止项
|
||||
|
||||
- 不要从本页 `operator` 示例外推未写入文档的重载族。
|
||||
- 不要把 `mcell` / `mrow` / `mcol` / `::` / `:.` 直接写成可用语法。
|
||||
- 重载 `::` / `:.` 遍历时,不要漏掉配套的 `mcell` / `mrow` / `mcol` / `mIndexCount` / `mIndex` 重载,否则遍历体会报 `override function not found`。
|
||||
- 不要把多级 `[]` 下标重载或 `value + obj` 这类右侧算术写成文档事实。
|
||||
- 不要在本页发明普通类语法;基础对象模型回 [08_objects_and_classes.md](08_objects_and_classes.md)。
|
||||
|
||||
@@ -90,6 +90,6 @@
|
||||
|
||||
## 切换到别的层
|
||||
|
||||
- 数据仓库金融函数:见 [../reference/catalog/datawarehouse.md](../reference/catalog/datawarehouse.md)
|
||||
- 数据仓库金融函数:见 [../codegen/dotnet/datawarehouse/](../codegen/dotnet/datawarehouse/)
|
||||
- 模块 / 集成 / 互操作:见 [../modules/index.md](../modules/index.md)
|
||||
- 函数库查找:见 [../reference/index.md](../reference/index.md)
|
||||
- 函数库查找:见 [../codegen/index.md](../codegen/index.md)
|
||||
|
||||
Reference in New Issue
Block a user