# 08 高级语言(新一代) 本章汇总新一代语法与相关机制。 ## 目录 - [高级语言(新一代)](#高级语言新一代) - [内容](#内容) - [复数](#复数) - [内容](#内容-1) - [定义](#定义) - [数据类型](#数据类型) - [复数运算](#复数运算) - [相关模型](#相关模型) - [WeakRef 弱引用(新一代)](#weakref弱引用新一代) - [内容](#内容-2) - [产生弱引用的背景](#产生弱引用的背景) - [弱引用](#弱引用) - [自动弱引用](#自动弱引用) - [当前版本对弱引用支持的判定](#当前版本对弱引用支持的判定) - [对象对基础算符与基础函数的重载](#对象对基础算符与基础函数的重载) - [内容](#内容-3) - [TSL 对象支持对二进制函数的重载](#tsl对象支持对二进制函数的重载) - [TSL 对象对遍历算符的重载](#tsl对象对遍历算符的重载) ## 高级语言(新一代) ### 内容 - 复数 - WeakRef 弱引用(新一代) - 对象对基础算符与基础函数的重载 ### 复数 形如 a+bi(a、b 均为实数)的数为复数,其中,a 被称为实部,b 被称为虚部,i 为虚数单位。 复数通常用 z 表示,即 z=a+bi 当 z 的虚部 b = 0 时,则 z 为实数; 当 z 的虚部 b≠0 时,实部 a = 0 时,常称 z 为纯虚数。 TSL 语言中支持复数的表达,虚数单位用 j 表示,记复数 z 为 a+bj,也支持复数的运算以及基础函数的应用。 目前仅新一代客户端与新一代服务器支持复数的相关功能。 #### 内容 - 定义 - 数据类型 - 复数运算 - 相关模型 #### 定义 在 TSL 语言中, 虚数单位用 j 表示,记复数 z 为 a+bj 通过常量定义方式或函数 complex(a,b)可以生成复数及复数矩阵 如:z:=4+3j 或 z:=complex(4,3) 即表示 z 是一个实部为 4,虚部为 3 的复数。 复数在客户端中的显示如下: 复数矩阵的生成 如:complex(array((1,2,3),(4,5,6)),array((-1,-2,-3),(1,2,3))) 生成一个 2\*3 的矩阵,显示如下: 也可借助矩阵初始化函数,如:complex(ones(2,3),ones(2,3)) 生成一个 2\*3 的实部与虚部都为 1 的复数矩阵,显示如下: 随机矩阵:complex(rand(3,2),rand(3,2)) #### 数据类型 在 TSL 语言中, datatype(v)可以判断任意数据的数据类型,而复数的数据类型对应的是分类 41。也可以通过 ifcomplex(z)进行判断是否是复数。 注意,虽然实数也属于复数,但是 ifcomplex 会判定实数(没有用 j 表示的数)为假,而 datatype 也同理。 例如: ```text Z:=4+3j; Return datatype(z); ``` 返回整型 41。 在解释器中直接运行如下: #### 复数运算 支持复数的基础运算,如四则运算、矩阵运算、集合运算、赋值运算等,具体可查看列表。 在使用上与实数一致,例如,有复数 z1 与 z2,分别如下: z1:=4+3j; z2:=5+12j; 加法: return z1+z2; 返回:9.0+15.0j 减法: Return Z2-z1; 返回:1.0+9.0j 乘法: Return z1\*z2; 返回:-16.0+63.0j 除法: Return z2/z1; 返回:2.24+1.32j ##### 内容 - 复数支持的算符列表 ##### 复数支持的算符列表
运算符 运算 运算对象 结果 举例
+ 复数、复数Array、 复数FMArray 支持与实数混合运算 复数、复数Array、 复数FMArray 1+2j+(2+3j)结果为3.0+5.0j
- 减,负号 同上 同上 2+3j-(3+1j)结果为-1.0+2.0j
* 同上 同上 (2+3j)*(3+1j)结果为3.0+11.0j
/ 同上 同上 (2+3j)/(3+1j)结果为0.9+0.7j
\ 左除 同上 同上 (3+1j)\(2+3j)结果为0.9+0.7j
~ 求对数 同上 同上 (8.0+6.0j)~(3+1j)结果为2.0+0.0j
^ 求幂 同上 同上 (3+1j)^2结果为8.0+6.0j
求倒数 一元运算符 单个值时求倒数,对矩阵时则是求矩阵逆 同上 !(3+1j)结果为0.3-0.1j
++ 加1 一元运算符 同上 (a:=(3+1j),a++,a)结果为4.0+1.0j
-- 减1 一元运算符 同上 (a:=(3+1j),a--,a)结果为2.0+1.0j
= 等于 复数、复数Array、 复数FMArray 支持与实数混合运算 布尔类型 (0+2j)=2j 结果为真
<> 不等 同上 布尔类型 (0+2j)<>2j结果为假
$ 字符串转换与拼接 复数、其它任意类型 字符串 (3+2j)$"A"结果为"3+2jA"
Like 相似判定 复数、复数Array、 复数FMArray 支持与实数混合运算 布尔类型、布尔矩阵 3.55+4.16j like 3.55 结果为假
赋值等于运算符
+= 加等于 复数、 复数Array、 复数FMArray 支持与实数混合运算 复数、 复数Array、 复数FMArray (a:=(3+1j),a+=(2+3j),a)结果为5.0+4.0j
-= 减等于 同上 同上 (a:=(3+1j),a-=(2+3j),a)结果为1.0-2.0j
*= 乘等于 同上 同上 (a:=(3+1j),a*=(2+3j),a)结果为3.0+11.0j
/= 除等于 同上 同上 (a:=(2+3j),a/=(3+1j),a)结果为0.9+0.7j
\= 左除等于 同上 同上 (a:=(3+1j),a\=(2+3j),a)结果为0.9+0.7j
^= 幂等于 同上 同上 (a:=(3+1j),a^=2,a)结果为8.0+6.0j
~= 对数等于 同上 同上 (a:=(8+6j),a~=(3+1j),a)结果为2.0+0.0j
矩阵运算符
:* 矩阵乘法 复数矩阵、 复数FMArray矩阵、支持与实数矩阵混合运算 复数Array、 复数FMArray 矩阵行列: n×m :* m×g =n×g a:=array((-1+1j),(-3+1j)); b:=array((2+2j,1+3j)); return a:*b; 结果为:array( (-4.0+0.0j,-4.0-2.0j), (-8.0-4.0j,-6.0-8.0j))
:/ 矩阵除法 同上 复数矩阵(Array、 FMArray) 矩阵行列: n×m :/ g×m=n×g a:=complex(rand(3,4),rand(3,4)); b:=complex(rand(5,4),rand(5,4)); return a:/b;
:\ 矩阵左除 同上 复数矩阵(Array、 FMArray) 矩阵行列: n×m :/ n×g=m×g a:=complex(rand(4,3),rand(4,3)); b:=complex(rand(4,5),rand(4,5)); return a:\b;
:^ 矩阵乘方 同上 复数Array、 复数FMArray 例如A:^3等于A:*A:*A,乘方应该是个方阵
:: 矩阵遍历 复数Array、复数FMArray、支持与实数数组混合运算 不改变原矩阵 a:=array((1+2j,2),(0,4+2j)); r:=0; a::r+=ifcomplex(mcell); return r;
::= 矩阵遍历并赋值 同上 对原矩阵进行重新赋值 a:=array((1+2j,2),(0,4+2j)); a::=ifcomplex(mcell); return a;
.= 矩阵等于 同上 与操作的矩阵结构相同,元素值为布尔值 a:=array((1+2j,2),(0,4+2j)); return a.=4+2j;
.<> 矩阵不等于 同上 同上 a:=array((1+2j,2),(0,4+2j)); return a.<>4+2j;
矩阵赋值运算
:*= 矩阵乘等于 复数矩阵、 复数FMArray矩阵、支持与实数矩阵混合运算 复数矩阵(Array、FMArray) 矩阵行列: n×m :* m×g =n×g a:=array((-1+1j),(-3+1j)); b:=array((2+2j,1+3j)); a:*=b; return a; 结果为:array( (-4.0+0.0j,-4.0-2.0j), (-8.0-4.0j,-6.0-8.0j))
:/= 矩阵除等于 同上 复数矩阵(Array、FMArray) 矩阵行列: n×m :/ g×m=n×g a:=complex(rand(3,4),rand(3,4)); b:=complex(rand(5,4),rand(5,4)); a:/=b; return a;
:\= 矩阵左除等于 同上 复数矩阵(Array、FMArray) 矩阵行列: n×m :/ n×g=m×g a:=complex(rand(4,3),rand(4,3)); b:=complex(rand(4,5),rand(4,5)); a:\=b; return a;
:^= 矩阵乘方等于 同上 复数Array、 复数FMArray a:=complex(rand(3,3),rand(3,3)); a:^=2 return a;
集合运算
| 矩阵右并 复数Array、复数FMArray、支持与实数数组混合运算 复数Array、 复数FMArray a:=complex(ones(2,2),ones(2,2)); b:=complex(zeros(3,2),zeros(3,2)); return a|b;
:| 非完全矩阵右并 同上 复数Array、 复数FMArray a:=complex(ones(2,2),ones(2,2)); b:=complex(zeros(3,2),zeros(3,2)); return a:|b;
Union 集合并集 同上 复数Array、 复数FMArray a:=complex(ones(2,2),ones(2,2)); b:=complex(zeros(3,2),zeros(3,2)); return a union b;
Union2 集合并集,有去重效果 同上 同上 a:=complex(ones(2,2),ones(2,2)); b:=complex(zeros(3,2),zeros(3,2)); return a union2 b;
Intersect 集合交集 同上 同上 a:=array(2+3j,3,2,1+2j); b:=array(1+2j,2,0,4+2j); return a intersect b;
Outersect 集合对称差集 同上 同上 a:=array(2+3j,3,2,1+2j); b:=array(1+2j,2,0,4+2j); return a Outersect b;
Minus 集合差集 同上 同上 a:=array(2+3j,3,2,1+2j); b:=array(1+2j,2,0,4+2j); return a Minus b;
In 存在于判定,以最小的元素进行判断 复数Array、复数FMArray、支持与实数数组混合运算 布尔类型 a:=4+2j; b:=array((1+2j,2),(0,4+2j)); return a in b;
sqlin 存在于判定,以行进行判断 同上 同上 a:=array(0,4+2j); b:=array((1+2j,2),(0,4+2j)); return a sqlin b;
集合赋值运算
|= 右并等于 复数Array、复数FMArray、支持与实数数组混合运算 复数Array、 复数FMArray a:=complex(ones(2,2),ones(2,2)); b:=complex(zeros(3,2),zeros(3,2)); a|=b; return a;
:|= 非完全矩阵右并等于 同上 同上 a:=complex(ones(2,2),ones(2,2)); b:=complex(zeros(3,2),zeros(3,2)); a:|=b; return a;
&= 集合合并等于 同上 同上 a:=complex(ones(2,2),ones(2,2)); b:=complex(zeros(3,2),zeros(3,2)); a&=b; return a;
Union2= 集合合并等于,并去重 同上 同上 a:=complex(ones(2,2),ones(2,2)); b:=complex(zeros(3,2),zeros(3,2)); a union2=b; return a;
Intersect= 集合交集等于 同上 同上 a:=array(2+3j,3,2,1+2j); b:=array(1+2j,2,0,4+2j); a Intersect=b; return a;
Outersect= 集合对称差集等于 同上 同上 a:=array(2+3j,3,2,1+2j); b:=array(1+2j,2,0,4+2j); a Outersect=b; return a;
Minus= 集合差集等于 同上 同上 a:=array(2+3j,3,2,1+2j); b:=array(1+2j,2,0,4+2j); a Minus=b; return a;
#### 相关模型 ##### 内容 - 复数生成 - 复数的虚部 - 共轭复数 - 复数的判定 - 基础函数对复数的支持 - 支持复数矩阵的函数列表 - 复数支持的相关说明 ##### 复数生成 ###### 内容 - Complex ###### Complex 范例 范例 01:生成一个复数 ```text Return complex(3,4); ``` // 3.0+4.0j 范例 02:生成一个复数矩阵 ```text return complex(array(1,2,3),5.5);//一维复数array return complex(array((1,2),(3,4)),array((1,2),(3,4)));//二维复数array return omplex(fmarray[1,2,3],5.5);//一维复数FMarray return complex(fmarray[[1,2],[3,4]],fmarray[[1,2],[3,4]]);//二维复数FMarray //生成随机复数矩阵 Return complex(rand(3),rand(5)); ``` ##### 复数的虚部 ###### 内容 - Imag ###### Imag 范例 范例 01: ```text z:=4+3j; z1:=4; z2:=3j; echo imag(z); echo imag(z1); echo imag(z2); ``` 打印结果为: 3 0 3 范例 02:数组的应用 ```text z:=4+3j; z1:=4; z2:=3j; t:=array(z,z1,z2); return imag(t); ``` 返回:array(3.0,0.0,3.0) ##### 共轭复数 ###### 内容 - conj ###### conj 范例 范例 01: ```text z:=4+3j; return conj(z); //复数z的共轭复数 ``` 返回:4-3j 范例 02:数组的应用 ```text t:=array(4+3j,4,3j);return conj(t); ``` 返回:array(4.0-3.0j,4.0,0.0-3.0j) ##### 复数的判定 ###### 内容 - IfComplex ###### IfComplex 范例 ```text //当参数为复数类型变量时,返回true。 Return IfComplex(1+2j);//返回1 Return IfComplex(1);//返回0 //判断数组中的元素时,通过N控制判定的单位 Return ifComplex(array(1,1+2j),1);//对数组中的每个元素进行判定,返回array(0,1) ``` ##### 基础函数对复数的支持 除了支持复数特定的功能模型外,已有的部分基础函数也支持复数的运算。 比如 abs 函数可以获取复数的模,如 abs(4+3j)的结果为 5。 Real 函数可以获取复数的实部,如 real(4+3j)的结果为 4。 这类函数也支持复数数组操作,包括 Array 及 FMArray 如 Real(array(1+2j,2.5+3j))的结果为 array(1.0,2.5)。 当个别函数不支持数组操作时,也可通过循环遍历运算符快速实现,此种方式只适合 Array 数组,不适合 FMArray,如: A:= array(1+2j,2.5+3j); A::=real(mcell); Return A; 返回的结果为:array(1.0,2.5) ###### 内容 - 复数支持的常用函数列表 ###### 复数支持的常用函数列表
No 函数名 功能 举例
1 Complex 构建复数或复数矩阵 Complex(1,2)返回1+2j
2 IfComplex 判断是否为复数 IfComplex(1+2j)返回1
3 Datatype 判断数据类型 复数的编号为41 Datatype(1+2j)返回41
4 real 取实部 如real(2.5+3.2j)返回实数2.5
5 Imag 取虚部 如Imag(2.5+3.2j)返回实数3.2
6 Conj 共轭复数 如Conj (2.5+3.2j)返回2.5-3.2j
7 Abs 取模 如Abs(3+4j)返回复数的模5
8 Minit 初始化FMArray 如Minit(3,1+2j)
9 Minitdiag 对角矩阵初始化FMArray 如MinitDiag(3,3,1+0j);
10 Sqr 求平方 如Sqr(3+1j)
11 Sqrt 求平方根 如sqrt(5+12j)
12 dupValue 复制值 如dupValue(2+1j)
13 Integer 强制转换为整数 如Integer(3.33+2.5j)结果为3
14 Int64 对实部进行取整 int64(2.5+1.6j)返回2
15 log10 以10为底的对数 如log10(2+1j)
16 Log2 以2为底的对数 如log2(2+1j)
17 LogN 以指定N为底的对数 如LogN(3,2+1j)
18 Int 将实部与虚部保留整数部分 int(2.5+1.6j) 返回2.0+1.0j
19 Frac 对实部与虚部进取小数部分 Frac(6.4-3.2j)返回0.4-0.2j
20 Ceil 对实部与虚部进行向上取整 Ceil(6.1+3.5j)结果为7.0+4.0j
21 Ceil32 对实部与虚部进行向上取整 Ceil32(6.1+3.5j)结果为7.0+4.0j
22 Ceil64 对实部与虚部进行向上取整 Ceil64(6.1+3.5j) 结果为7.0+4.0j
23 Floor 对实部与虚部进行向下取整 Floor(6.1+3.5j)结果为6.0+3.0j
24 Floor32 对实部与虚部进行向下取整 Floor32(6.1+3.5j)结果为6.0+3.0j
25 Floor64 对实部与虚部进行向下取整 Floor64(6.1+3.5j)结果为6.0+3.0j
26 Trunc 对实部与虚部进行近0取整 Trunc(6.1-3.2j)结果为6.0-3.0j
27 Trunc32 对实部与虚部进行近0取整 Trunc32(6.1-3.2j)结果为6.0-3.0j
28 Trunc64 对实部与虚部进行近0取整 Trunc64(6.1-3.2j)结果为6.0-3.0j
精度相关函数,对实部与虚部分别进行处理
29 FloatN 四舍五入 如:FloatN(2145.3456-1234.3446j,2) 返回:2145.35-1234.34j
30 RoundTo5 .5处理 RoundTo5(2.45-21.05j) 返回:2.5-21.0j
31 RoundTo 四舍五入,银行家算法 roundto(123.3446-123.3446j,-2) 返回:123.34-123.34j
32 SimpleRoundTo 四舍五入 simpleroundto(2154.3456-1246.3456j,2) 返回:2200.0-1200.0j
33 Round 四舍五入后输出整数,银行家算法 round(2145.3456-1234.3456j) 返回:2145.0-1234.0j
34 round32 四舍五入后输出整数,银行家算法 round32(6.5+3.5j) 返回:6.0+4.0j
35 round64 四舍五入后输出整数,银行家算法 Round64(6.5+3.5j) 返回:6.0+4.0j
36 simpleround 四舍五入后输出整数 simpleround(6.5+3.5j) 返回:7.0+4.0j
37 simpleround32 四舍五入后输出整数 simpleround32(6.5+3.5j) 返回:7.0+4.0j
38 simpleround64 四舍五入后输出整数 Simpleround64(6.5+3.5j) 返回:7.0+4.0j
其它基础函数
39 IsZero 在指定精度下是否等于0,可用于判断两个值是否相等 IsZero(0.000001+0.0001j,0.00001)结果为0
40 ToStn 转换成STN字符串 如tostn(2.2+3.5j)返回字符串的” 2.2+3.5j”
41 Stn 将串转成任意类型 如stn(“1+2j”)返回复数1.0+2.0j
42 Format 将数值转换成指定格式字符串 如Format("%.3f",2.55+4.1j)返回字符串” 2.550+4.100j”
43 DivValue 除运算 如DivValue(2+3j,3+4j)等同于(2+3j)/( 3+4j)
44 Eval 执行表达式 如eval(&"2+3.22+3.14j")返回5.22+3.14j
45 call 调用函数 如call("abs",3-4j) 返回5
46 CallInarray 调用函数 如callInarray("abs",array(3-4j))返回5
##### 支持复数矩阵的函数列表 除基础函数支持对复数矩阵的操作外,如统计函数、分解函数等也支持复数矩阵的运算,具体列表如下:
No 函数名 功能 与实数处理的差异
1 IfComplex 判断每个元素是否为复数,如 ifComplex(array(2,2j),1)
2 Datatype 返回每个元素的数据类型的编号,如 Datatype(array(2,2j),1)
3 arraytofm 将Array数组转成FMarray矩阵 如arraytofm(t,2j)
4 ExportCsv 将数组转成csv字符串,如 ExportCsv(array((2+3j,1+2j),(2,3)),s)
….其它数据类型的判定函数
统计函数 具体用法请查看官方函数说明
1 Mean 求算术平均值
2 Sum 求和
3 sumInt 对实部和虚部分别求整数部分和 算法: sumint(real(a))+sumint(imag(a))*1j
4 SumOfSquares 求数组平方和
5 Norm 求数组平方和的平方根 在复数的计算中,a*conj(a)会替代平方,因此Norm的算法为: sqrt(sum(a*conj(a))) 虚部恒为0,所以norm仅返回实部的值
6 SumsAndSquares 计算总和以及平方和
7 StdDev 样本标准差 算法中计算平方由a*conj(a)替代,其它不变
8 PopnStdDev 总体标准差 算法中计算平方由a*conj(a)替代,其它不变
9 Variance 样本方差 算法中计算平方由a*conj(a)替代,其它不变
10 PopnVariance 总体方差 算法中计算平方由a*conj(a)替代,其它不变
11 TotalVariance 总体偏差 算法中计算平方由a*conj(a)替代,其它不变
12 MeanAndStdDev 计算平均值和标准差 标准差算法同StdDev
13 Geomean 几何平均数
14 Harmean 调和平均数
15 Mode 众数
16 AveDev 均值绝对偏差
17 DevSq 样本平均值偏差的平方和 算法中计算平方由a*conj(a)替代,其它不变
18 Product 累乘值
19 Randomfrom 从一组数据中随机抽取一个样本
20 VariationCoefficient 变异系数 算法中计算平方由a*conj(a)替代,其它不变,需等升级
双序列统计函数
1 Cov 协方差 E[X-ux*Conj(Y-uy)]
2 Correl 相关系数 Cov与PopnStdDev符合复数运算
3 Slopeandintercept 回归斜率和截距
4 Slope 回归斜率
5 Intercept 回归截距
6 RSQ 乘积矩相关系数平方
7 Steyx 相对标准偏差
8 BetaAndAlpha 斜率和截距
9 MeanAndPopnStdDevWithRate 带权重总体标准差以及平均值
矩阵运算及分解
1 mt_Transposition 矩阵转置
2 mt_Multiplication 矩阵乘
3 mt_Addition 矩阵和
4 mt_Subtraction 矩阵差
5 Mt_decompose_lu 进行lu分解, 函数输出中vi为0,wr为复数特征值
6 Mt_decompose_qr 对矩阵进行QR分解
7 Mt_decompose_eig 特征值及特征向量
8 Mt_decompose_chol cholesky分解
9 Mt_decompose_svd 进行SVD分解 实矩阵验证方式: U :* (eye(n,m)*s) :* `v 复矩阵验证方式: U :* (eye(n,m)*s) :* conj(`v)
10 Mt_decompose_ldl ldl分解
##### 复数支持的相关说明 ###### 内容 - 复数与实数的等于判定 - 关于 Norm 的算法说明 - 统计函数的支持复数的范围说明 - 双序列统计函数中不支持 FMarray 与其它数组 Array 混合运算 - 在统计函数中,目前复数版本和实数版本是分开的,不支持混合运算 ###### 复数与实数的等于判定 如:实数 3.15 与复数 3.15+0j。 在值上两者相等,即 3.15=3.15+0j 为真 在集合运算中,由于两者值虽等,但数据类型不一致,所以不能判定为同一个数,因此,在做去重合并及交集差集时,它两不会被认为是同一个元素。 而在 FMArray 中,由于数据类型必段保持一致,所以在进行集合运算时,当既存在 3.15 又存在 3.15+0j 时,会将 3.15 强制转换成 3.15+0j,最后再进行合并处理。与 Array 的结果会存在差异。 ###### 关于 Norm 的算法说明 Norm:一般定义:计算一组数据的平方和的平方根,也就是 Sqrt(SumOfSquares) 而在复数序列中,复数的计算是 a*conj(a)替代平方,在求 norm 的时候,所以标准差的计算也是如此。即复数中算法为 sqrt(sum(a*conj(a))),而由于其虚部恒为 0,所以 norm 仅返回实数部的值。 由此,在其它统计类函数方法中,也有类似的处理,如标准差等,在上面列表中有特别提示说明。 ###### 统计函数的支持复数的范围说明 数组统计类函数对复数的支持(包括 FMARRAY 以及 ARRAY),包含单序列以及双序列。包括如 cov,correl,斜率,截距,stddev,popnstddev...等等统计类函数,也包括简单的 sum,mean 之类的都支持,但任何和大小相关的都不支持,即如 median,max,min 类的统计函数、分位数及频度统计相关函数,牵涉到大小的,另一个是定义存在问题的偏度和峰度未做支持(因为统计意义我们没有找到其定义)。 ###### 双序列统计函数中不支持 FMarray 与其它数组 Array 混合运算 如 cov\correl 等 不支持如第一个参数为 fmarray 序列,而第二个参数为 Array 序列。 ###### 在统计函数中,目前复数版本和实数版本是分开的,不支持混合运算 原因是,全支持的代价较大,且意义不大,因为复数本身使用少,不能因复数影响实数计算。因此,用户在使用时,应该将数据处理成全实数或全复数。目前的假设,实数当复数可用,复数当实数需要满足虚部为 0。 即,不支持运算如 sum(array(1,1+2j)) 这种操作,会报错。用户在使用时,应该将所有值转成复数后再处理,如将 1 转成 1+0j 即可。 在实际应用中,当数组中既有实数,又有复数时,我们可以将数组中的实数批量转换成复数,方法如下: 第一种:循环遍历方式 t:=array(1,1+2j); t::=ifComplex(mcell)?mcell:complex(mcell,0); return t; 第二种:复数重构 t:=array(1,1+2j); return complex(real(t),imag(t)); 转换后结果如下: 转换完成后,就可以进行 sum(t)的操作了。 ### WeakRef 弱引用(新一代) 为解决对象的循环引用问题,我们引入的弱引用这个概念,本章节中主要介绍它的产生背景、解决的问题及详细使用说明。 特别说明:弱引用目前只在下一代全新测试服务器中支持。 #### 内容 - 产生弱引用的背景 - 弱引用 - 自动弱引用 - 当前版本对弱引用支持的判定 #### 产生弱引用的背景 TSL 对象的生命周期中,采用的是引用计数模式,依赖对象的引用计数。 在对对象进行赋值等操作时,不是新增一个对象,而是指向该对象,并用引用数来记录该对象的生命周期。其过程为,当创建或引用对象时会使引用计数加 1,失去引用时将使得引用计数减 1,当引用计数为 0 时,会对该对象进行释放,这就是对象的一个完整的生命周期。 为了诠释这个过程,我们可以看下面这段代码: ```text A:=new TA(); //创建一个实例对象,增加一个引用数(创建对象,yN=1) B:=A; //B指向A的实例对象,增加一个引用数(yN=2) Echo "Set A to NIL\r\n"; A:=nil; //注销对象,引用数减一(yN=1) Echo "Set B to NIL\r\n"; B:=nil; //注销对象,引用数减一(yN=0,此时对象被完全释放) Echo "Run end\r\n"; Type TA=class Public Function Destroy(); Begin Echo "Destroy\r\n"; End; End; ``` 执行后打印结果为: Set A to NIL Set B to NIL Destroy Run end 从这个打印结果可以看出,创建对象 A 并被赋值给 B 后,当设置 A 的值为 nil 时(即注释原 A 创建的对象),该对象并没有直接被析构,而是等到 B 也被赋值为 nil 时,才被析构释放。 这种采用对象引用计数的设计它的优势有易于使用,不会非法引用,生命周期可以自动管理,性能高,低内存开销等。有些类似于 CopyOnWrite 模式,当将对象赋值给另一个变量时不会对内存进行拷贝,而只是产生引用计数。与 CopyOnWrite 的区别是,即便是对对象进行写入,也不会产生新的对象,而是直接与入当前对象。 采用引用计数在方便应用的同时,也带来了循环引用的问题。那么,什么是循环引用?再看一段代码:

A:=new TA();
Echo "Set A to NIL\r\n";
A:=nil;
Echo "Run end\r\n";
Type TA=class
FB;
Public
Function Create();
Begin
FB:=new TB(self);
end;
Function Destroy();
Begin
Echo "Destroy\r\n";
End;
End;

type TB=class
FOwner;
Public
function create(Owner);
begin
FOwner:=Owner;
end;
end;
打印结果:
Set A to NIL
Run end
通过上面的代码可以看出,A 创建了一个 TA 实例对象,而在创建的时候 T.FB 指向了类 TB 的一个实例,而 TB 在创建实例时,又将 A.FB.Fowner 指向了 A,于是就产生了循环引用,这时,通过打印结果可以看出,将 A 设置为 nil 时,立马做了 Echo “Run end\r\n”操作,而没有对实例对象进行析构(Destroy()方法没有被执行),这是为什么呢? 原因是循环引用会让自身拥有多一个引用计数,循环引用后,引用计数因为自身的循环引用导致永远无法被减到 0。 也就是说循环引用会导致对象无法被释放,这类对象我们称之为无主对象,即垃圾对象。这种情况会导致原对象的析构函数无法被执行以及当产生很多垃圾对象时会导致占用许多内存,影响内存开销。 循环引用的主要产生场景 可以看出,在上面这些场景下,循环引用是必然会发生的事情,在这种情况下,用户就需要主动对循环引用对象在不需要的时候提前进行解耦,显然,这种方式下应用起来是比较麻烦的,因此,天软引入弱引用,能够比较好地解决该问题。我们本文中重点就是介绍,如何使用弱引用解决在对象中存在的循环引用问题。 #### 弱引用 ##### 内容 - 弱引用的定义 - 弱引用支持的类型 - MakeWeakref - weakref_get:生成强引用定义 2 - Weakref - WeakRef:创建弱引用定义 2 - MakeStrongref - MakeStrongref:生成强引用定义 2 - weakref_get - MakeWeakref:创建弱引用定义 2 - CheckWeakRef - weakref_check - 采用弱引用解决循环引用的问题 ##### 弱引用的定义 前面讲到,在 TSL 对象的生命周期中,依赖对象的引用计数。为了区别,当对对象进行引用时,被引用对象的引用数会加 1 的引用,我们称之为强引用,相对应的,对对象进行引用时,被引用对象的引用数不增加,但依然引用该对象,我们称之为弱引用。 弱引用的特点: 1 弱引用自身拥有引用计数。 2 弱引用不会增加被引用对象的引用数,不会参与到被引用对象的生周期中。 3 在探测到对象被释放时,不会引发异常。 弱引用支持范围:对象、带类信息的对象、对象成员方法。 注:弱引用是基于强引用产生的,弱引用的使用应该是针对需要弱引用的场景使用,没必要时不需要使用。 ##### 弱引用支持的类型 1 对象类型 2 含有当前类信息的对象类型,如 self 返回的对象 3 对象的成员函数 即,包含有对象的类型均需要支持弱引用 ##### MakeWeakref 范例 范例 01:弱引用的创建与对被引用对象引用数的影响 ```text A:=New TA("A"); B:=makeweakref(A); echo "B.FA--",B.FA; echo "Set A to nil"; A:=nil; echo "A---End"; return 1; Type TA=class public FA; Function Create(v); begin echo "Create--",v; FA:=v; end Function Destroy(); begin echo FA,"-Destroy!"; end end; ``` 打印: Create--A B.FA--A Set A to nil A-Destroy! A---End 解析:B.FA 返回”A”,说明 B 引用 A 指向的对象;当 A 设置为 nil 时,A 对应的对象被成功释放,即 B:=makeweakref(A);没有导致 A 指向的对象的引用数加 1,B 是一个弱引用。 ##### weakref_get:生成强引用定义 2 范例 范例 02:weakref_get 定义二,错误引用不报错 ```text B:= weakref_get (10,r);//类型不支持。 return r;//返回0 ``` ##### Weakref 范例 范例 01:WeakRef 定义一,创建弱引用 ```text A:=New TStringList(); //创建一个字符串对象 A.Append("A"); B:=weakref(A); //创建一个弱引用 B.Append("B"); return B.CommaText; //返回逗号分割的字符串 ``` ##### WeakRef:创建弱引用定义 2 范例 范例 02:WeakRef 定义二,错误引用不报错 ```text B:= WeakRef (10,r);//类型不支持。 return r;//返回0 ``` ##### MakeStrongref 范例 范例 01:通过弱引用对象创建一个强引用 ```text A:=New TStringList(); A.Append("A"); B:=weakref(A);//创建弱引用 B.Append("B"); C:=MakestrongRef(B);//通过弱引用对象产生一个强引用 C.Append("C"); return C.CommaText; ``` 返回结果: A,B,C ##### MakeStrongref:生成强引用定义 2 范例 范例 02:MakestrongRef 定义二,错误引用不报错 ```text B:= MakestrongRef (10,r);//类型不支持。 return r;//返回0 ``` ##### weakref_get 范例 范例 01:通过弱引用对象创建一个强引用 ```text A:=New TStringList(); A.Append("A"); B:=weakref(A); B.Append("B"); C:= weakref_get (B);//通过弱引用对象产生一个强引用 C.Append("C"); return C.CommaText; ``` 结果: A,B,C ##### MakeWeakref:创建弱引用定义 2 范例 范例 02:MakeWeakRef 定义二,错误引用不报错 ```text B:=makeweakref(10,r);//类型不支持。 return r;//返回0 ``` ##### CheckWeakRef 范例 ```text A:=New TStringList(); B:=weakref(A); //弱引用 D:=B; return checkweakref(B); ``` 返回结果:2 ##### weakref_check 范例 ```text A:=New TStringList(); B:=weakref(A); //弱引用 return weakref_check(B); ``` 返回结果:1 ##### 采用弱引用解决循环引用的问题

A:=new TA();
Echo "Set A to NIL\r\n";
A:=nil;
Echo "Run end\r\n";

Type TA=class
FB;
Public
Function Create();
Begin
FB:=new TB(self);
end;
Function Destroy();
Begin
Echo "Destroy\r\n";
End;
End;

type TB=class
FOwner;
Public
function create(Owner);
begin
FOwner:=MakeWeakRef(Owner);
end;
end;

打印结果:
Set A to NIL
Destroy
Run end

这种方式可以解决循环引用的问题,但是操作起来较为麻烦,用户需要知道在什么情况下会产生循环引用,然后再到指定位置去进行增加控制,这种写法容易错漏,当需要的弱引用较多时,编写也比较繁琐,也不容易维护,因此,为了开发方便天软还提供了自动弱引用的方式。 #### 自动弱引用 对设定标的赋值操作进行自动弱引用。主要约定的是类的成员变量。 ##### 内容 - 自动弱引用关键字 - 设置当前环境下的变量为自动弱引用 - 设定指定变量为自动弱引用 - 自动弱引用规则的起效规则 - 自动弱引用解决循环引用的问题 ##### 自动弱引用关键字 Weakref:自动弱引用 Autoref:取消自动弱引用 引发循环引用的来源均来自于类成员变量,即 1 类成员变量直接引用 2 类成员数组间接引用。 所以自动弱引用的作用范围:类成员变量,默认为 Autoref。 ###### 内容 - Weakref - Autoref ###### Weakref 自动弱引用,即启动后,后面定义的成员变量都为弱引用。 ###### Autoref 不自动弱引用,即启动后,后面定义的成员变量不再自动为弱引用,一般用于取消弱引用。 ##### 设置当前环境下的变量为自动弱引用 可通过设置关键字 WeakRef 启动弱引用,使其下面定义的变量自动设置为弱引用,AutoRef 为关闭弱引用,即恢复默认的强引用。 同时定义多个弱引用变量,实现代码如下: ```text Type AutoWeakTest=class FA; WeakRef //定义下方的成员变量为弱引用 FOnClick; FOnDBLClick; FOnMouseMove; FOnMouseOver; AutoRef //解除弱引用的定义,即下方成员变量为默认的强引用 FB; FC; End; ``` 解读:其中, FA 是初始模式,所以未自动弱引用。 WeakRef 打开 AutoWeakTest 类的成员变量自动弱引用开关。 FOnClick,FOnDBLClick,FOnMouseMove,FOnMouseOver; 为自动弱引用 AutoRef 关闭 AutoWeakTest 类的成员变量自动弱引用开关, FB,FC 为非自动弱引用。 这种方式类似 Public,Private,Protected,但 WeakRef,AutoRef 是约定是否自动弱引用,且仅对成员变量起效。可视域和自动弱引用的约定互相不干扰。 ##### 设定指定变量为自动弱引用 语法: [WeakRef] x1[,x2,…]; 指定成员 x1(或 x2 等,多个变量用,隔开)为自动弱引用 [AutoRef]x1[,x2,…]; 指定成员 x1(或 x2 等,多个变量用,隔开)为强引用,一般在弱引用设定环境下使用。 即带[ ]只对当前语句中的变量有效,不带[]就是对段落有效。 范例: ```text Type AutoWeakTest2=class FA; [WeakRef]FB,FB2,FB3;//在强引用环境下,定义弱引用 FC; WeakRef //指定当前环境下定义的成员为弱引用 FOnClick; [AutoRef]FD; FOnMouseMove; FOnMouseOver; End; ``` 即,上面的强引用成员变量有:FA,FC,FD; 弱引用成员变量有:FB,FB2,FB3,FonClick, FonMouseMove, FonMouseOver。 ##### 自动弱引用规则的起效规则 1 直接对自动弱引用的成员变量进行赋值 2 对 property write 指定的成员变量赋值 即,若 property A write B 中,B 是弱引用或者 B(v)方法中存在对弱引用的成员变量进行赋值,则在对 A 进行写入时(A:=obj),B 此时产生的引用也是弱引用。 3 将成员变量作为参数送入 TSL 开发的函数,在函数内对参数赋值 即,在类的方法中将成员变量作为参数送入到被调用的函数中,在函数内对参数赋值 4 对数组成员变量进行下标设置 ArrayData[下标]:=Obj 即,成员变量 ArrayData 是弱引用,且 ArrayData 是一个数组,在对这个数组的指定元素进行赋值操作时,也是弱引用。 应用场景说明: 1 目前 C++等开发而成的二进制函数和方法不支持自动弱引用规则,需要支持的函数要用新的接口进行改写。 2 弱引用规则主要为了实现 TSL 语言层的对象循环引用。 3 二进制函数基本不存在和 TSL 语言对象之间的循环引用问题。 4 如果存在其他情况需要用户使用 MakeWeakRef 来实现。 ##### 自动弱引用解决循环引用的问题

A:=new TA();
Echo "Set A to NIL\r\n";
A:=nil;
Echo "Run end\r\n";
Type TA=class
FB;
Public
Function Create();
Begin
FB:=new TB(self);
end;
Function Destroy();
Begin
Echo "Destroy\r\n";
End;
End;
type TB=class
[WeakRef]FOwner;
Public
function create(Owner);
begin
FOwner:=Owner;//弱引用
end;
end;

打印结果:
Set A to NIL
Destroy
Run end

其中,Fowner 是自动弱引用成员变量,在对自动弱引用的成员变量进行赋值时,产生的引用为弱引用,至此,循环引用就得到了很好的解决。 #### 当前版本对弱引用支持的判定 弱引用功能目前只在最新版的解释器中支持,用户可以通过条件编译的方式判断当前版本的解释器中是否支持弱引用及自动弱引用功能。 1、条件编译判定是否支持弱引用 {$IFDEF weakptr} {$ENDIF} 2、条件编译支持判定是否支持自动弱引用 {$IFDEF AutoWeak} {$ENDIF} 范例: ```text //判断当前解释器是否支持弱引用 {$IFDEF weakptr} echo "Support weakptr"; {$ELSE} echo "Unsupport weakptr"; {$ENDIF} //判断当前解释器是否支持自动弱引用 {$IFDEF AutoWeak} echo 'Support AutoWeak'; {$ELSE} echo "Unsupport AutoWeak"; {$ENDIF} return 1; ``` 当前版本支持弱引用时打印: Support weakptr Support AutoWeak 当前版本不支持弱引用时打印: Unsupport weakptr Unsupport AutoWeak ### 对象对基础算符与基础函数的重载 #### 内容 - TSL 对象支持对二进制函数的重载 - TSL 对象对遍历算符的重载 #### TSL 对象支持对二进制函数的重载 为了更好地支持天软新一代节点网状关系数据库 TSNETDB 及符号计算等特殊应用,并对 GPU、NPU 等扩展计算提供基础支撑,天软进行了如下功能的新增: 1、在原有算符重载以及 TS-SQL 重载的基础之上,新增了 TSL 对象支持对二进制函数的重载,例如二进制函数 abs/sin/cos 等。 即既支持二进制类用 C 等语言扩展重载对象的函数(为 GPU/NPU 等计算提供支撑),也支持 TSL 开发的类重载二进制函数。 对于 TSL 对象,支持使用如下方式进行重载二进制函数: 2、使用类方法实现 3、使用对象成员函数实现 此外,进行重载时还支持具有变参返回的函数,如 TryStrToInt。 注:二进制函数指的是天软客户端中无法查看其源代码的系统或公用函数,其往往是使用更加底层的语言如 C、C++等实现的。下图是函数 RoundTo 在客户端中的展示。 ##### 内容 - 二进制函数在 TSL 对象中的重载 - 对象中对二进制函数重载的应用 ##### 二进制函数在 TSL 对象中的重载 定义:[class] function operator funcNmane([,p1[,p2[,…]]]); 说明:其中 class 关键字表示定义为类方法,为可选关键字。 Operator:为重载关键字 funcName:为被重载的二进制函数名 p1,p2,…:函数参数列表。支持通过参数传出返回值。 当重载函数被定义为类方法时,应该保持与原函数参数个数一致。 当被定义为对象成员函数时,参数个数应该比原函数参数少 1 个;会以第一个参数的对象实例调用该成员函数。 在 TSL 对象中对二进制函数进行重载,需要注意以下几点: 1、方法定义时,需在方法名前加上 operator 关键字 2、在类中,如需调用全局函数,可在函数调用前加上::。 全局函数:在任何位置都可以被调用到的函数,如系统函数、公用函数、用户函数等。 局部函数:只在指定范围内可被调用到的函数,比如子函数,及类方法等。 即,当存在同名函数时,在需要调用全局函数时可使用::进行指定。 3、使用此种方式重载的函数仅支持二进制函数,不支持使用 TSL 代码实现的函数 4、关键字(关键字函数)的重载不需要使用::。 ###### 内容 - 1、使用类方法实现二进制函数重载的示例 - 2、使用成员函数实现二进制函数重载的示例 - 3、重载函数支持通过参数传出返回值的示例 ###### 1、使用类方法实现二进制函数重载的示例 现有整数类 IntDate,代码如下: ```text type IntDate=class value; function create(v) begin value:=v; end class function operator DateToStr(t) begin t:=ifObj(t)?t.value:t; endt:=IntToDate(t); return DateToStr(endt); end end ``` 其中,创建了类方法 DateToStr,实现了对二进制函数 DateToStr 的重载。 在调用时,可以使用如下两种方式: ```text d:=new IntDate(20240329); return DateToStr(d); //方式一 return class(IntDate).DateToStr(20240329); //方式二 ``` 结果:返回字符串"2024-03-29" ###### 2、使用成员函数实现二进制函数重载的示例 现有类 IntDate,代码如下: ```text type IntDate=class value; function create(v) begin value:=v; end function operator DateToStr() begin v:=IntToDate(value); return DateToStr(v); end end ``` 其中,创建了成员函数 DateToStr,实现了对二进制函数 DateToStr 的重载。 调用方式如下: ```text d:=new IntDate(20240329); return DateToStr(d); ``` 结果:返回字符串"2024-03-29" ###### 3、重载函数支持通过参数传出返回值的示例 以成员函数重载为例,现有类 classA,代码如下: ```text type classA=class value; function operator TryStrToInt(msg); begin return ::TryStrToInt(value,msg); //使用::调用全局方法 end; end ``` 其中,创建了成员函数 TryStrToInt,实现了对二进制函数 TryStrToInt 的重载。 当运行如下调用代码时: ```text c:=new classA(); c.value:="314"; ret:=TryStrToInt(c,msg); return array(ret,msg); ``` 结果: 可以看到,字符串” 314”成功被转换成整数类型,并且结果被赋值给了参数 msg。 ##### 对象中对二进制函数重载的应用 ###### 内容 - 1、范例:类 TsDate-对整数日期的扩展 ###### 1、范例:类 TsDate-对整数日期的扩展 如下所示,类 TsDate 对天软日期的一些常用方法进行了重载,使得整数日期可直接调用这些方法。 ```text td:=new TsDate(20240329); echo "字符串日期","---->",DateToStr(td); echo "整数日期","---->",DateToInt(td); DecodeDate(td,year,month,day); echo "指定日期的年月日(成员方法)","---->","year:"$year," ","month:"$month," ","day:"$day; class(TsDate).DecodeDate(20240329,y,m,d); echo "指定日期的年月日(类方法)","---->","year:"$y," ","month:"$m," ","day:"$d; echo "所在年份","---->",YearOf(td); echo "所在月份","---->",MonthOf(td); echo "所在日","---->",DayOf(td); echo "所在年份的第一天","---->",StartOfTheYear(td); echo "所在年份的最后一天","---->",EndOfTheYear(td); echo "所在月份的第一天","---->",StartOfTheMonth(td); echo "所在月份的最后一天","---->",EndOfTheMonth(td); echo "所在周的第一天","---->",StartOfTheWeek(td); echo "所在周的最后一天","---->",EndOfTheWeek(td); echo "向前推移5年","---->",IncYear(td,-5); echo "向前推移5月","---->",IncMonth(td,-5); echo "向前推移5天","---->",IncDay(td,-5); ``` 其中,类 TsDate 实现代码如下: ```text type TsDate=class Ftd; function create(td) begin Ftd:=Init(td); end function operator DateToStr() begin return ::DateToStr(Ftd); end function operator DateToInt() begin return ::DateToInt(Ftd); end function operator YearOf() begin return ::YearOf(Ftd); end function operator MonthOf() begin return ::MonthOf(Ftd); end function operator DayOf() begin return ::DayOf(Ftd); end class function operator DecodeDate(td,year,month,day) begin v:=ifObj(td)?td.Ftd:Init(td); return ::DecodeDate(v,year,month,day); end function operator StartOfTheYear() begin return ::DateToInt(::StartOfTheYear(Ftd)); end function operator EndOfTheYear() begin return ::DateToInt(::EndOfTheYear(Ftd)); end function operator StartOfTheMonth() begin return ::DateToInt(::StartOfTheMonth(Ftd)); end function operator EndOfTheMonth() begin return ::DateToInt(::EndOfTheMonth(Ftd)); end function operator StartOfTheWeek() begin return ::DateToInt(::StartOfTheWeek(Ftd)); end function operator EndOfTheWeek() begin return ::DateToInt(::EndOfTheWeek(Ftd)); end function operator IncYear(y) begin return ::DateToInt(::IncYear(Ftd,y)); end function operator IncMonth(m) begin return ::DateToInt(::IncMonth(Ftd,m)); end function operator IncDay(d) begin return ::DateToInt(::IncDay(Ftd,d)); end class function Init(td) begin return ifstring(td)?StrToDate(td):((td>=0 and td<=99991231T)?td:IntToDate(td)); end end ``` 运行结果如下: #### TSL 对象对遍历算符的重载 ##### 内容 - for in 循环在对象中的重载 - 关键字 msize,mrows,mcols 在对象中的重载 - ::,:.,mcell,mrow,mcol,mIndexCount,mIndex 等算符在对象中的重载 ##### for in 循环在对象中的重载 定义: function operator for(flag:integer); 说明: Operator:为重载关键字 flag:整型,运行标识,由两位二进制数字组成,低位表示是否不是初始化状态, 高位表示 for in 中是否有两个循环变量。因为我们普通的 for in 有 for a in t do 与 for a,b in t do 两种语法。 如 0b10(十进制 2)表示第一次循环且有两个循环变量;0b11(十进制 3)表示非第一次循环且有两循环变量; 循环过程中,若返回 nil 则表示循环结束,若为数值则表示循环继续。 ###### 内容 - For in 循环在对象中重载的示例 ###### For in 循环在对象中重载的示例 实际对对象进行 for in 循环时,对对象的 data 属性进行循环操作。 ```text a:=array("A","B","C"); echo "For in table---------\r\n"; for n,v in a do begin echo n,"->",v,"\r\n"; end; echo "For in obj-一个变量---------\r\n"; c1:=new c(a); for n in c1 do begin echo n,"\r\n"; end; echo "For in obj-两个变量---------\r\n"; for n,v in c1 do begin echo n,"->",v,"\r\n"; end; return; type c=class public data; lengtD; findex; function create(v); begin data:=v; lengtD:=length(v); end; function operator for(flag);//flag控制参数个数,n,v begin n:=flag .& 2;//n即为高位数值,1表示两个变量,0表示只有一个变量 b:=flag .& 1;//b即为低位数值,1表示不是第一次循环,0表示第一次循环 echo "--for--:",flag," flag高位:",n," flag低位:",b,"\r\n"; if not b then //循环开始初始化 findex:=0 else if findexA 1->B 2->C For in obj-一个变量--------- --for--:0 flag 高位:0 flag 低位:0 0 --for--:1 flag 高位:0 flag 低位:1 1 --for--:1 flag 高位:0 flag 低位:1 2 --for--:1 flag 高位:0 flag 低位:1 For in obj-两个变量--------- --for--:2 flag 高位:2 flag 低位:0 0->A --for--:3 flag 高位:2 flag 低位:1 1->B --for--:3 flag 高位:2 flag 低位:1 2->C --for--:3 flag 高位:2 flag 低位:1 解析:通过上面的过程可以看出,我们可以在对象中对 for in 操作进行重载实现,通过对 flag 的控制,可以实现每次循环过程中对对象的操作。 打印结果中,两个循环变量的循环中,高位值为 2 是因为代表二进制数值 0b10,即二进制中高位为 1。 ##### 关键字 msize,mrows,mcols 在对象中的重载 定义:[class] function operator KeyWord([p1[,p2[,…]]]); 说明:其中 class 关键字表示定义为类方法,为可选关键字。 Operator:为重载关键字 KeyWord:表示关键字函数,如 msiz,mrows,mcols 等 p1,p2,…:函数参数列表。支持通过参数传出返回值。 当重载函数被定义为类方法时,应该保持与原函数参数个数一致。 当被定义为对象成员函数时,参数个数应该比原函数参数少 1 个;会以第一个参数的对象实例调用该成员函数。用法同二进制函数的重载。 注:关键字不需要::进行指定全局函数。 ###### 内容 - 关键字函数在对象中重载的示例 ###### 关键字函数在对象中重载的示例 以重载关键字函数 mcols(data,n)以及二进制函数 length 为示例。 ```text c1:=new c(); echo c1.length()," ",length(c1),"\r\n"; echo mcols(c1),"\r\n";//返回列数 echo tostn(c1.mcols(1)),"\r\n"; //返回列下标 return ; type c=class fa; function create(); begin fa:=array(("A":1,"B":2,"C":3),("A":5,"B":5,"C":5)); end; function operator mcols(n); function operator length(); begin return ::length(fa); end; end; function operator c.mcols(n); begin _n:=ifnil(n)?0:n; return mcols(fa,_n); end; ``` 打印结果: 2 2 3 array("A","B","C") 解析:通过上面的示例,可看出关键字的重载与调用跟对二进制函数的操作非常相似。 ##### ::,:.,mcell,mrow,mcol,mIndexCount,mIndex 等算符在对象中的重载 定义:function operator KeyWord([p1[,p2[,…]]]); 说明: Operator:为重载关键字 KeyWord:表示关键字函数,如::,:.,mcell,mrow,mcol,mIndexCount,mIndex 等 p1,p2,…:函数参数列表。 其中,在::与:.遍历过程中,有一个参数,该参数为 0 时表示第一次循环,为 1 时表示非第一次循环。 循环过程中,返回 0 或 nil 表示循环结束,非 0 数字则表示循环继续。 重载示例(模拟相关算符与关键字在数组中的功能): ```text type c1=class public data; Rdata; findex; lengtD; function create(v); begin data:=v; end; function operator ::(flag);//flag:0表示第一次循环;1表示非第一次循环 ,最多支持二维 begin // echo "::flag ",flag; 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 findex2 then for i:=2 to mIndexCount-1 do Rdata[k,i+2]:=mIndex(i); k++; end lengtD:=length(Rdata); findex:=0; end else if findex3,"B":10->2,"C":20->21,"D":30->23);//不完全矩阵 t["B",1]:=array(801,802,803); //多维矩阵 obj:=new c1(t); echo "::遍历"; obj::begin s:="mcell:"$mcell$" mrow:"$mrow$" mcol:"$mcol$" mIndexCount:"$mIndexCount; for i:=0 to mIndexCount-1 do s+=" mIndex("$i$"):"$mIndex(0); echo s; end echo ":.深度遍历"; obj:.begin s:="mcell:"$mcell$" mrow:"$mrow$" mcol:"$mcol$" mIndexCount:"$mIndexCount; for i:=0 to mIndexCount-1 do s+=" mIndex("$i$"):"$mIndex(0); echo s; end return 1; ``` 打印结果: ::遍历 mcell:0 mrow:A mcol:0 mIndexCount:2 mIndex(0):A mIndex(1):A mcell:1 mrow:A mcol:1 mIndexCount:2 mIndex(0):A mIndex(1):A mcell:2 mrow:A mcol:2 mIndexCount:2 mIndex(0):A mIndex(1):A mcell:3 mrow:A mcol:3 mIndexCount:2 mIndex(0):A mIndex(1):A mcell: mrow:B mcol:1 mIndexCount:2 mIndex(0):B mIndex(1):B mcell:20 mrow:C mcol:0 mIndexCount:2 mIndex(0):C mIndex(1):C mcell:21 mrow:C mcol:1 mIndexCount:2 mIndex(0):C mIndex(1):C :.深度遍历 mcell:0 mrow:A mcol:0 mIndexCount:2 mIndex(0):A mIndex(1):A mcell:1 mrow:A mcol:1 mIndexCount:2 mIndex(0):A mIndex(1):A mcell:2 mrow:A mcol:2 mIndexCount:2 mIndex(0):A mIndex(1):A mcell:3 mrow:A mcol:3 mIndexCount:2 mIndex(0):A mIndex(1):A mcell:801 mrow:B mcol:1 mIndexCount:3 mIndex(0):B mIndex(1):B mIndex(2):B mcell:802 mrow:B mcol:1 mIndexCount:3 mIndex(0):B mIndex(1):B mIndex(2):B mcell:803 mrow:B mcol:1 mIndexCount:3 mIndex(0):B mIndex(1):B mIndex(2):B mcell:20 mrow:C mcol:0 mIndexCount:2 mIndex(0):C mIndex(1):C mcell:21 mrow:C mcol:1 mIndexCount:2 mIndex(0):C mIndex(1):C