Skip to main content
运算符决定表达式的组合与求值顺序。本章汇总核心运算符,并说明它们的优先级与结合性,便于阅读复杂表达式。

运算符总览

算术运算符

算术运算符用于数值计算,同时也支持部分字符串、集合等运行时扩展的实现:
运算符描述示例
+加法1 + 2
-减法&a - 3
*乘法&price * &count
/除法&total / &n
%取模&i % 2
^幂运算2 ^ 10
幂运算符 ^ 具有右结合性,即 2^3^2 会被解析为 2^(3^2) = 2^9 = 512,而不是 (2^3)^2 = 64
result1 = 2 ^ 10       # => 1024
result2 = 2 ^ 3 ^ 2    # => 512(右结合:2^(3^2) = 2^9)

比较运算符

比较运算符返回布尔结果,可用于条件与分支:
运算符描述示例
==相等&a == &b
!=不相等&status != ok
>大于&score > 90
<小于&x < 0
>=大于等于&n >= 1
<=小于等于&n <= 100
is类型检查&obj is string

类型检查运算符 is

is 运算符用于运行时类型检查,返回布尔值:
result1 = "hello" is string    # true
result2 = 123 is int            # true
result3 = [1, 2, 3] is list     # true
result4 = null is string        # false(null 始终返回 false)
语法规则:
  • 形式:<expr> is <TypeName>
  • 右侧必须是类型字面量,不能是表达式
  • 类型在解析期解析并缓存,运行时直接进行类型检查
支持的类型别名(不区分大小写):
别名Java 类型
string / Stringjava.lang.String
int / Intjava.lang.Integer
long / Longjava.lang.Long
float / Floatjava.lang.Float
double / Doublejava.lang.Double
boolean / Booleanjava.lang.Boolean
list / Listjava.util.List
map / Mapjava.util.Map
set / Setjava.util.Set
使用完全限定类名:
obj = new java.util.ArrayList()
check = &obj is java.util.ArrayList    # true
在 when 表达式中使用: is 运算符可以在 when 表达式中作为分支匹配条件:
typeDesc = when &obj {
    is string -> "文本"
    is int -> "整数"
    is list -> "列表"
    else -> "其他类型"
}
详见 控制流 章节。

逻辑运算符

逻辑运算符使用“真值语义”而不是仅限布尔类型,内部会调用运行时的 isTrue 判定:
运算符描述示例
&&逻辑与&ok && &enabled
||逻辑或&fallback || &primary
!逻辑非!&flag
逻辑运算符具有短路行为:
  • a && b:当 a 为假时,不再计算 b
  • a || b:当 a 为真时,不再计算 b

赋值与复合赋值

赋值运算符用于更新变量的当前值,结合引用运算符 & 在表达式中读取结果:
运算符描述示例等价形式
=简单赋值x = 1
+=加法赋值sum += &nsum = &sum + &n
-=减法赋值x -= 1x = &x - 1
*=乘法赋值total *= 2total = &total * 2
/=除法赋值avg /= 10avg = &avg / 10
%=取模赋值i %= 2i = &i % 2

特殊运算符

Fluxon 还提供若干与控制流和语义糖相关的运算符:
运算符描述示例
..区间(闭区间)1..10
..<区间(左闭右开)0..< &n
?:Elvis 运算符&name ?: "anonymous"
&变量引用运算符sum = &a + &b
::上下文调用运算符&list :: size()
?::安全上下文调用&obj ?:: transform()
.成员访问(反射)&user.name / &list.size()
?.安全成员访问(反射)&obj?.name / &obj?.size()
这些运算符在其他章节中有详细说明,本章主要关心它们在大表达式中的优先级关系。

运算符优先级

Fluxon 的表达式解析采用自顶向下递归下降和优先级划分。
类别示例
括号与字面量(expr)[1, 2][k: v]
成员访问与函数调用obj.nameobj?.namef(x)
上下文调用&target :: func()&obj ?:: transform()
一元运算符!expr-expr&name
幂运算^(右结合)
乘除模*/%
加减+-
范围运算符....<
比较与类型检查> >= < <= == !=is
逻辑与/或&&、``
Elvis 运算符?:
赋值与复合赋值=+=-=
括号 (...) 总是可以强制改变默认优先级:
result1 = 1 + 2 * 3      # 等价于 1 + (2 * 3) = 7
result2 = (1 + 2) * 3    # 等于 9

一元运算符与引用

一元运算符写在操作数前面:
flag = !&ok
delta = -&n
sum = &a + &b
引用 (&) 的优先级高于大多数二元运算符,因此 &a + &b 会被解析为 (&a) + (&b),而不是 &(a + b) 如果需要对整个表达式结果取引用(在部分语法中),应显式添加括号。

逻辑短路与结合方向

逻辑运算符是 左结合 的:
a && b && c    # 解析为 (a && b) && c
a || b || c    # 解析为 (a || b) || c
短路行为配合左结合,使得从左到右依次检查条件成为自然写法:
ready = &configLoaded && &connectionOk && &authorized

Elvis 运算符

Elvis 运算符 ?: 用于在左侧为 null 时返回右侧默认值:
name = &input ?: "anonymous"
它的优先级低于算术、比较和逻辑运算,一般规则是:
  • 先计算 &input 的值。
  • 如果结果为 null,返回右侧表达式的值;否则返回左侧。
如需限定参与 ?: 的子表达式范围,可以使用括号:
value = (&a + &b) ?: 0

安全访问运算符

Fluxon 提供两种安全访问运算符,用于处理可能为 null 的目标:

安全成员访问 ?.

当目标为 null 时返回 null,而不是抛出 NullPointerException
// 如果 obj 为 null,返回 null
name = &obj?.name
length = &obj?.length()

// 链式安全访问
result = &a?.b?.c

安全上下文调用 ?::

当目标为 null 时返回 null,而不是执行右侧的上下文表达式:
// 如果 obj 为 null,返回 null
result = &obj ?:: transform()
result = &obj ?:: { uppercase() }

// 链式安全上下文调用
result = &obj ?:: transform() ?:: format()

与 Elvis 组合

安全访问常与 Elvis 运算符配合,提供默认值:
// 安全访问 + 默认值
name = &user?.name ?: "anonymous"
size = (&list ?:: size()) ?: 0

赋值的结合方向

赋值语句通常按从左到右依次执行更新,更推荐拆成多行,而不是写成链式形式:
b = 1
a = &b
这样更利于阅读和调试,也避免对赋值结果是否可参与运算的误解。

与上下文调用、函数调用的组合

上下文调用运算符 :: 与函数调用优先级较高,它们在解析时会先于算术与逻辑运算生效:
result = &list :: filter(fn) :: size() > 0 && &enabled
大致解析为:
  1. 先对 &list 做上下文调用,得到 filter(fn) 的结果。
  2. 再在该结果上做第二次 :: size() 调用。
  3. size() 的返回值与 0 做比较。
  4. 最后与 &enabled&& 运算。
如需改变这一顺序,可以照常使用括号包裹需要整体计算的部分。

推荐写法

  • 对于复杂表达式,宁可 多写括号 来表达意图,而不是依赖读者记住所有优先级规则。
  • 在涉及 && / || 与函数调用、上下文调用混用时,建议按 “每行一个逻辑步骤” 的方式拆分。
  • 对赋值表达式的值有依赖时,推荐显式拆出中间变量,有助于调试和日志记录。

相关链接