运算符
Aria 提供了丰富的运算符,涵盖算术、赋值、比较、逻辑、位运算以及多种特殊运算符。
算术运算符
基本的数学运算:
a = 10 + 3 // 13.0
b = 10 - 3 // 7.0
c = 10 * 3 // 30.0
d = 10 / 3 // 3.333...
e = 10 % 3 // 1.0
除以 0 不抛异常,结果为
0.0。
自增和自减支持前缀与后缀两种形式:
i = 5
i++ // 后缀自增,表达式值为 5,之后 i = 6
++i // 前缀自增,i 先变为 7,表达式值为 7
i-- // 后缀自减,表达式值为 7,之后 i = 6
--i // 前缀自减,i 先变为 5,表达式值为 5
++ / -- 按「加 1 / 减 1」的值模型工作,对非数字也适用(见下文特殊运算规则):
x = 'a' 后执行 x++,x 变为 'a1.0'(字符串拼接语义)。
赋值运算符
x = 10 // 基本赋值
x += 5 // x = x + 5 → 15.0
x -= 3 // x = x - 3 → 12.0
x *= 2 // x = x * 2 → 24.0
x /= 4 // x = x / 4 → 6.0
x %= 5 // x = x % 5 → 1.0
注意:裸名与
var./val.是完全隔离的命名空间(读写互不回退)。var.x = 10后写x += 5操作的是另一个变量(裸名x,初值none),var.x仍是 10。复合赋值请与声明使用同一命名空间。详见变量系统。
~= 是初始化或获取运算符,仅在变量未定义时赋值:
var.name ~= 'default' // 如果 var.name 未定义,则赋值为 'default'
位运算赋值:
bits = 0b1100
bits &= 0b1010 // 按位与赋值 → 0b1000
bits |= 0b0011 // 按位或赋值 → 0b1011
bits ^= 0b1111 // 按位异或赋值 → 0b0100
bits <<= 2 // 左移赋值
bits >>= 1 // 右移赋值
bits >>>= 1 // 无符号右移赋值
比较运算符
a = 10 == 10 // true
b = 10 != 5 // true
c = 10 < 20 // true
d = 10 > 5 // true
e = 10 <= 10 // true
f = 10 >= 15 // false
== 的比较规则:
- 双方都可作为数字时按数值比较:
10 == '10'为true; - 任一侧是不可转数字的字符串时,双方都退化为字符串比较:
true == 'true'为true; - 其余情况按值语义比较。
10 == '10' // true(数值比较)
true == 'true' // true(字符串回退)
true == 'yes' // false
~~ 区间匹配运算符
~~ 检查左侧的值是否落在右侧的 Range 内。右侧不是 Range 时结果恒为 false
(不退化为相等性检查):
x = 5
a = x ~~ Range(1, 10) // true:Range 为双端闭区间 [1, 10],含 1 也含 10
b = 10 ~~ Range(1, 10) // true(end 含入)
c = x ~~ 1..10 // 同上:`1..10` 是 `Range(1, 10)` 的字面量简写
d = x ~~ 5 // false!右侧非 Range 一律 false
e = x ~~ 'hello' // false
a..b 是区间字面量,等价于 Range(a, b)(双端闭,步长 1);需要自定义步长时用
Range(a, b, step)。可直接用于 ~~ 和 for-in。
Range 为双端闭区间:
Range(1, 10)(或字面量1..10)包含 1 到 10。start > end且未显式给步长时为空区间(不会自动倒序遍历); 显式Range(10, 1, -1)仍可倒序。与for (i in Range(...))的遍历范围一致。
真值规则
条件位置(if / while / ? : / && / || / !)按以下规则求真值:
| 类型 | 真值 |
|---|---|
| boolean | true / false 本身 |
| number | 大于 0 为真(0、负数为假) |
| string | 仅字符串 'true' 为真('yes'、'1'、'2' 均为假) |
| none | 假 |
| list/map | 非空为真 |
| 函数/对象 | 一般为假(宿主对象默认 booleanValue = false) |
0.5 ? 'yes' : 'no' // 'yes'(> 0)
-1 ? 'yes' : 'no' // 'no'
'true' ? 'yes' : 'no' // 'yes'
'2' ? 'yes' : 'no' // 'no'!数字字符串不按数值取真值
逻辑运算符
a = true && false // false(逻辑与)
b = true || false // true(逻辑或)
c = !true // false(逻辑非)
逻辑运算符支持短路求值:&& 在左侧为假时不计算右侧,|| 在左侧为真时不计算右侧。
位运算符
a = 0b1100 & 0b1010 // 0b1000(按位与)
b = 0b1100 | 0b1010 // 0b1110(按位或)
c = 0b1100 ^ 0b1010 // 0b0110(按位异或)
d = ~0b1100 // 按位取反
e = 1 << 3 // 8(左移)
f = 16 >> 2 // 4(右移)
g = -1 >>> 28 // 无符号右移 → 15
三元运算符
标准三元表达式:
result = (x > 0) ? 'positive' : 'non-positive'
Elvis 变体 — 省略中间部分或末尾部分:
a = x ? : defaultVal // x 为真返回 x,否则返回 defaultVal
b = x ? 'yes' : // x 为真返回 'yes',否则返回 none
可选链
?. 在对象为 none 时安全地返回 none,而不是抛出错误:
name = user?.name // user 为 none 时返回 none
len = list?.length() // list 为 none 时返回 none
空值合并
?? 在左侧为 none 时返回右侧的值:
name = user?.name ?? 'anonymous'
port = config?.port ?? 8080
成员检查运算符
in 检查键是否存在于 map 或对象中:
m = {'name': 'Aria', 'version': 1}
exists = 'name' in m // true
missing = 'age' in m // false
注意:对列表,
in检查的是索引是否有效(而非值成员)。 如0 in [10, 20, 30]为 true(索引 0 存在),3 in [10, 20, 30]为 false(长度 3,无索引 3)。 判断列表是否包含某个值用list.contains(value)。
instanceof 检查对象是否为指定类的实例:
class Animal {}
class Dog extends Animal {}
d = Dog()
isDog = d instanceof Dog // true
isAnimal = d instanceof Animal // true(支持继承链)
展开运算符
... 用于展开列表或字典:
a = [1, 2, 3]
b = [0, ...a, 4] // [0, 1, 2, 3, 4]
base = {'x': 1}
extended = {...base, 'y': 2} // {'x': 1, 'y': 2}
在字典字面量中展开非 map 值(列表、数字、none 等)会抛出运行时错误。
函数箭头
-> 用于定义函数:
var.add = -> {
return args[0] + args[1]
}
行首运算符续行
一行以特定运算符开头时会与上一行折叠为同一表达式。折叠集合为:
. ? : && || , < ==(注意 + - * = ( [ { 不折叠):
m = {'a': 1}
n = m
.size() // 折叠为 m.size() → 1.0
x = true
? 1
: 2 // x = true ? 1 : 2 → 1.0
行首 ( 不折叠:x = f 与下一行的 (3) 是两条独立语句(后者为无效果的表达式语句)。
运算符优先级
从高到低排列:
| 优先级 | 运算符 | 说明 |
|---|---|---|
| 1(最高) | () [] . ?. | 调用、索引、成员访问 |
| 2 | ++ --(后缀) | 后缀自增自减 |
| 3 | ! - ~ ++ --(前缀) | 一元运算符 |
| 4 | * / % | 乘法、除法、取模 |
| 5 | + - | 加法、减法 |
| 6 | << >> >>> | 位移 |
| 7 | < > <= >= ~~ in instanceof | 比较、区间/成员检查 |
| 8 | == != | 相等 |
| 9 | & | 按位与 |
| 10 | ^ | 按位异或 |
| 11 | | | 按位或 |
| 12 | ?? | 空值合并 |
| 13 | && | 逻辑与 |
| 14 | || | 逻辑或 |
| 15 | ? : | 三元运算符 |
| 16(最低) | = += -= *= /= %= ~= 等 | 赋值 |
区间字面量
..的优先级介于位移(<<等)与比较(<~~等)之间:x ~~ 1..10会先构造1..10再做区间判断,for (i in a..b)亦同。
特殊运算规则
Aria 对不同类型之间的运算有特殊处理(与 Shimmer 引擎逐条对齐,含其历史怪癖)。
数字与字符串
- 字符串的”数字性”:任何字符串都会尝试按
Double.parseDouble判定能否作为数字, 拼接产生的新字符串会重新判定。因此'' + 0得'0.0'(可作数字),再+ 1走数值加法得1.0。 number + string:字符串可转数字则数学加法(1 + '2'→3.0); 否则数字先转字符串再拼接(1 + 'a'→'1.0a','slot' + 1→'slot1.0'——数字恒为N.0格式)。string + string:双方都可转数字则数值加法('2' + '3'→5.0);否则拼接。string - string:双方可转数字则减法('5' - '2'→3.0); 否则从左侧字符串中删除右侧子串('aXbXc' - 'X'→'abc')。number - 非数字字符串:从数字的字符串形式中删除该子串(1 - 'a'→'1.0',结果是字符串)。- 一元负号
-x:x为不可转数字的字符串时抛错(字符串内容非数字);对 list/map 抛不支持的反转操作。
布尔值参与算术
true + 1→2.0、false + 1→1.0(布尔按 1/0 与数字相加);true + true→'truetrue'(布尔相加走字符串拼接);true + '1'→'true1'(与数字字符串相加也走拼接);true - 1→2.0(减法数字分支实际执行的是加法);true - '1'→'true'、true - 'x'→'true'(字符串分支按”删除子串”处理)。
列表与字典
list + list:把右侧元素原地追加到左侧列表并返回同一个列表(非新列表);list + 元素:原地追加该元素,返回同一个列表;list - number:按索引删除([1, 2, 3] - 0→[2, 3]);list - list:删除右侧列表中包含的元素;list - 其它值:按Math.abs(该值转整数)当索引删除([10,20,30] - '1'删索引 1);map + map:合并两个字典,右侧覆盖左侧的同名键;map - key:移除指定键;map + 非 map:抛出运行时错误。
非法操作数
数字与 list/map 相加减(如 1 + [1])等无意义组合会抛出运行时错误
(number 类型不支持与 list 类型进行加法运算 等),错误格式见异常处理。