Aria 提供了丰富的运算符,涵盖算术、赋值、比较、逻辑、位运算以及多种特殊运算符。
基本的数学运算:
val.a = 10 + 3 // 13
val.b = 10 - 3 // 7
val.c = 10 * 3 // 30
val.d = 10 / 3 // 3.333...
val.e = 10 % 3 // 1
自增和自减支持前缀与后缀两种形式:
var.i = 5
i++ // 后缀自增,表达式值为 5,之后 i = 6
++i // 前缀自增,i 先变为 7,表达式值为 7
i-- // 后缀自减,表达式值为 7,之后 i = 6
--i // 前缀自减,i 先变为 5,表达式值为 5
var.x = 10 // 基本赋值
x += 5 // x = x + 5 → 15
x -= 3 // x = x - 3 → 12
x *= 2 // x = x * 2 → 24
x /= 4 // x = x / 4 → 6
x %= 5 // x = x % 5 → 1
~= 是初始化或获取运算符,仅在变量未定义时赋值:
var.name ~= 'default' // 如果 name 未定义,则赋值为 'default'
位运算赋值:
var.bits = 0b1100
bits &= 0b1010 // 按位与赋值 → 0b1000
bits |= 0b0011 // 按位或赋值 → 0b1011
bits ^= 0b1111 // 按位异或赋值 → 0b0100
bits <<= 2 // 左移赋值
bits >>= 1 // 右移赋值
bits >>>= 1 // 无符号右移赋值
val.a = 10 == 10 // true
val.b = 10 != 5 // true
val.c = 10 < 20 // true
val.d = 10 > 5 // true
val.e = 10 <= 10 // true
val.f = 10 >= 15 // false
~~ 是模糊匹配运算符,主要用于检查一个值是否落在某个 Range 内。对于非 Range 类型,~~ 会退化为相等性检查(等价于 ==)。
val.inRange = x ~~ Range(1, 10) // 检查 x 是否在范围 [1, 10)(左闭右开,含 1 不含 10)
val.eq = x ~~ 'hello' // 非 Range 类型,等价于 x == 'hello'
Range 为左闭右开区间:Range(1, 10) 包含 1..9,不含 10。与 for (i in Range(...)) 的遍历范围一致。
val.a = true && false // false(逻辑与)
val.b = true || false // true(逻辑或)
val.c = !true // false(逻辑非)
逻辑运算符支持短路求值:&& 在左侧为假时不计算右侧,|| 在左侧为真时不计算右侧。
val.a = 0b1100 & 0b1010 // 0b1000(按位与)
val.b = 0b1100 | 0b1010 // 0b1110(按位或)
val.c = 0b1100 ^ 0b1010 // 0b0110(按位异或)
val.d = ~0b1100 // 按位取反
val.e = 1 << 3 // 8(左移)
val.f = 16 >> 2 // 4(右移)
val.g = -1 >>> 28 // 无符号右移
标准三元表达式:
var.result = (x > 0) ? 'positive' : 'non-positive'
Elvis 变体 — 省略中间部分或末尾部分:
var.a = x ? : defaultVal // x 为真返回 x,否则返回 defaultVal
var.b = x ? 'yes' : // x 为真返回 'yes',否则返回 none
?. 在对象为 none 时安全地返回 none,而不是抛出错误:
val.name = user?.name // user 为 none 时返回 none
val.len = list?.length() // list 为 none 时返回 none
?? 在左侧为 none 时返回右侧的值:
val.name = user?.name ?? 'anonymous'
val.port = config?.port ?? 8080
in 检查键是否存在于 map 或对象中:
val.m = {'name': 'Aria', 'version': 1}
val.exists = 'name' in m // true
val.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 : Animal {}
val.d = new Dog()
val.isDog = d instanceof Dog // true
val.isAnimal = d instanceof Animal // true(支持继承链)
... 用于展开列表或字典:
val.a = [1, 2, 3]
val.b = [0, ...a, 4] // [0, 1, 2, 3, 4]
val.base = {'x': 1}
val.extended = {...base, 'y': 2} // {'x': 1, 'y': 2}
-> 用于定义函数:
var.add = -> {
return args[0] + args[1]
}
从高到低排列:
| 优先级 | 运算符 | 说明 |
|---|
| 1(最高) | () [] . ?. | 调用、索引、成员访问 |
| 2 | ++ --(后缀) | 后缀自增自减 |
| 3 | ! - ~ ++ --(前缀) | 一元运算符 |
| 4 | * / % | 乘法、除法、取模 |
| 5 | + - | 加法、减法 |
| 6 | << >> >>> | 位移 |
| 7 | < > <= >= ~~ in instanceof | 比较、成员检查 |
| 8 | == != | 相等 |
| 9 | & | 按位与 |
| 10 | ^ | 按位异或 |
| 11 | | | 按位或 |
| 12 | ?? | 空值合并 |
| 13 | && | 逻辑与 |
| 14 | || | 逻辑或 |
| 15 | ? : | 三元运算符 |
| 16(最低) | = += -= *= /= %= ~= 等 | 赋值 |
Aria 对不同类型之间的运算有特殊处理:
number + string:如果字符串可以转为数字,则执行数学加法;否则执行字符串拼接
string - string:如果双方都可以转为数字,则执行减法;否则从左侧字符串中删除右侧子串
list + list:合并两个列表,返回新列表
list - value:从列表中移除指定元素
map + map:合并两个字典,右侧覆盖左侧的同名键