这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战
幂运算
从 5.1.3 开始,AviatorScript 引入幂运算符 ** ,原来使用 math.pow(a, b) 的代码都可以写成 a**b ,幂运算符的优先级较高,在单目运算符之上。
p(2 ** 3);
p(2 ** -3);
p(2N ** 3);
p(2M ** 3);
p(2 ** 2.2);
输出:
8
0.125
8
8
4.59479341998814
幂运算的基本规则:
- 基数和指数都为 long ,并且指数为正数,结果为 long
- 基数和指数都为 long,并且指数为负数,结果为 double
- 基数为 decimal,指数取整数部分(int value),等价于
BigDecimal#pow(int)。 - 基数为 bigint,指数取整数部分(int value),等价于
BigInteger#pow(int)。
- 基数或者指数任一为 double,结果为 double
位运算
我们还没有介绍的是数字的位运算,位运算仅支持整数 long,并且跟 Java 完全保持一致:
&位与运算|或运算
^异或运算~一元非运算
<<左移运算>>右移运算
>>>无符号右移
看一个简单例子,比如我们通常用位运算来控制 flag 某个标记位:
## examples/bitwise.av
let OPEN = 0x01;
let flag = 0;
flag = flag | OPEN;
(flag & OPEN) == OPEN ? println("open") : println("close");
flag = flag &~ OPEN;
(flag & OPEN) == OPEN ? println("open") : println("close");
println("flag is " + flag);
运算符优先级
完整的运算符优先级的优先顺序如下表,基本跟 java 保持一致,除了特别引入的正则匹配:
| 优先级 | 运算符 | 结合性 | ||
|---|---|---|---|---|
| 1 | ( ) [ ] . | 从左到右 | ||
| 2 | ** | 从左到右 | ||
| 3 | ! ~ | 从右到左 | ||
| 4 | * / % | 从左到右 | ||
| 5 | + - | 从左到右 | ||
| 6 | << >> >>> | 从左到右 | ||
| 7 | < <= > >= | 从左到右 | ||
| 8 | == != | 从左到右 | ||
| 9 | & | 从左到右 | ||
| 10 | 从左到右 | |||
| 11 | 从左到右 | |||
| 12 | && | 从左到右 | ||
| 13 | 从左到右 | |||
| 14 | ? : | 从左到右 | ||
| 15 | = =~ | 从右到左 |
这里还出现了我们还没谈到的运算符 [] 用于数组或者集合访问,后面我们在降到集合类型的时候会详细介绍。
记住这个优先级没有太大必要,无论如何,都推荐使用括号来明确表示优先级。
自定义运算符
前面我们已经看了运算符重载的例子,比如加减乘除,可以用于 long/double/bigint/decimal 等多种数字类型,这就是一个重载,比如加号 + 可以用于数字,也可以用于拼接字符串,这又是一个重载。
你也可以自定义任意运算符的行为,比如我们想将整数相除的结果修改为浮点数,那么可以:
package com.googlecode.aviator.example;
import java.util.Map;
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.lexer.token.OperatorType;
import com.googlecode.aviator.runtime.function.AbstractFunction;
import com.googlecode.aviator.runtime.function.FunctionUtils;
import com.googlecode.aviator.runtime.type.AviatorDouble;
import com.googlecode.aviator.runtime.type.AviatorObject;
import com.googlecode.aviator.runtime.type.AviatorType;
/**
* An example to demo custom division operator.
*
* @author dennis(killme2008@gmail.com)
*
*/
public class CustomDivideExample {
public static void main(final String[] args) {
AviatorEvaluator.getInstance().addOpFunction(OperatorType.DIV, new AbstractFunction() {
@Override
public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,
final AviatorObject arg2) {
if (arg1.getAviatorType() == AviatorType.Long
&& arg2.getAviatorType() == AviatorType.Long) {
// If arg1 and arg2 are all long type.
// Cast arg2 into double and divided by arg1.
double d = FunctionUtils.getNumberValue(arg1, env).longValue()
/ FunctionUtils.getNumberValue(arg2, env).doubleValue();
return AviatorDouble.valueOf(d);
} else {
// Otherwise, call aviatorscript's div function.
return arg1.div(arg2, env);
}
}
@Override
public String getName() {
return OperatorType.DIV.getToken();
}
});
System.out.println(AviatorEvaluator.execute("1/2"));
}
}
通过 AviatorEvaluatorInstance#addOpFunction(opType, function) 就可以自定义运算符的行为,这个例子中如果我们发现 arg1/arg2 的类型都是 long ,那么我们就将 arg2 转成 double 并计算结果,结果需要包装成 AviatorDouble 类型返回;如果不是,我们继续调用原来的除法。
所有的运算符都可以在 OperatorType 找到,你都可以自定义他的行为。
从这个例子中我们也可以看出 AviatorScript 中的所有类型都是 AviatorObject 的子类,他们包括:
AviatorLong表示整数 long 类型AviatorDouble表示浮点数 double 类型
AviatorBigInt表示 bigint 大整数AviatorDecimal表示 decimal 类型
AviatorString表示字符串AviatorPattern表示正则表达式
AviatorNil特殊类型 nil,将在下一节变量中讲到AviatorJavaType表示变量,将在下一节讲到
可以参见 AviatorType 这个枚举类。所有运算符都实现为 AviatorObject 的一个方法,比如加法就是 add(arg2, env) ,减法就是 sub 等等,具体见 AviatorObject 文档。比较运算符的实现是基于 compare(arg2, env) 方法返回的结果,如果为 0 ,表示相等,大于返回正数,小于返回负数。