mvel语法指南[翻译]
- Property expressions
- Boolean expressions
- Method invocations
- Variable assignments
- Function definitions
一、基本语法:
statement1; statement2; statement3
a = 10;
b = (a = a * 2) + 10;
a;
二、mvel2.0的操作运算
Unary Operators
Operator |
Description |
Example |
---|---|---|
new |
Object instantiation |
new String("foo") |
with |
Block WITH Operator. Perform multiple operations on a single object instance |
with (value) { name = 'Foo', age = 18, sex = Sex.FEMALE } |
assert |
Assert that a value is true or fail with an AssertionError |
assert foo != null |
isdef |
Tests whether or not a variable is defined within the scope |
isdef variableName |
! |
Boolean negation operator |
!true == false |
Comparison Operators
Operator |
Description |
Example |
---|---|---|
== |
Equality Check. Checks to see if the values on both sides of the operator are equal. Unlike Java, this is not an identity check. |
"foo" == "foo" is true |
!= |
Not Equals Check. Checks to see if the values on both sides of the operator are not equal. |
"foo" == "bar" is false |
> |
Greater Than Check. Checks to see if the value on the left side of the operator is greater than than value on the right. |
2 > 1 is true |
< |
Less Than Check. Checks to see if the value on the left side of the operator is less than value on the right. |
1 < 2 is true |
>= |
Greater Than or Equal. Checks to see if the value on the left hand side is greater than or equal to the value on the right. |
1 >= 1 is true |
<= |
Less Than or Equal. Checks to see if the value on the left hand side is less than or equal to the value on the right. |
2 <= 2 is true |
contains |
Value Containment Check. Checks to see if the value on the left contains the value on the right. For more details on how this operator works, see Contains Operator |
var contains "Foo" |
is orinstanceof |
Type Checking Operator. Checks to see if the value on the left is a member of the class on the right. |
var instanceof Integer |
strsim |
String Similarity Check. Compares to strings and returns a similarity between them as a percentage. See: String Similarity Check. |
"foobie" strsim "foobar" |
soundslike |
Soundex Check. Performs a soundex comparison between two strings. See: Soundex. |
"foobar" soundslike "fubar" |
Logical Operators
Operator |
Description |
Example |
---|---|---|
&& |
Logical AND. Checks to see that the values on both sides of the operator are true. |
foo && bar |
|| |
Logical OR. Checks to see if either the value on the left or the right is true. |
foo || bar |
or |
Chained OR. Checks a sequence of values for emptinessand returns the first non-empty value. (This operator, or at least it's equivalent functionality, is referred to as the "elvis operator" in other languages) |
foo or bar or barfoo or 'N/A' |
~= |
Regular Expression Match. Checks to see if the value on the left matches the regular expression on the right. |
foo ~= '[a-z].+' |
Bitwise Operators
Operator |
Description |
Example |
---|---|---|
& |
Bitwise AND. |
foo & 5 |
| |
Bitwise OR. |
foo | 5 |
^ |
Bitwise XOR. |
foo ^ 5 |
Arithmetic Operators
Operator |
Description |
Example |
---|---|---|
+ |
Addition. Adds the value on the left to the value on the right |
1 + 2 |
- |
Subtraction. Subtracts the value on the right from the value on the left |
2 - 1 |
/ |
Division. Divides the number on the left by the number on the right |
2 / 1 |
* |
Multiplication. Multiples the number on the left by the number on the right |
1 * 2 |
% |
Modulus. Divides the number on the left by the number on the right and returns the remainder. |
2 % 1 |
Other Operators
Operator |
Description |
Example |
---|---|---|
+ |
String Concatenation. Overloaded operator for concatenating two strings together. |
"foo" + ;bar" |
# |
Concatenation Operator. Concatenates two literals as strings. |
1 # 2returns "12" |
in |
Projection/Fold. Projects across a collection. See:Projections and Folds. |
(foo in list) |
= |
Assignment. Assigns the value on the right to the variable on the left. |
var = "foobar" |
三、值测试
1:判断值是否为emptiness
MVEL提供了一个特殊的字符来表示值为emptiness的情况,叫作empty,如:foo == empty,若foo满足emptiness的任何条件,这个表达式值都为true
For example:
foo == empty
若foo满足emptiness的任何条件,这个表达式值都为true
2:测试null
foo == null;
foo == nil; // same as null
3:强制转换
"123" == 123;
四、内置集合
['Bob' : new Person('Bob'), 'Michael' : new Person('Michael')]
Map map = new HashMap();
map.put("Bob", new Person("Bob"));
map.put("Michael", new Person("Michael"));
这是一个非常强大的方式来表达MVEL内的数据结构。你可以在任何地方使用这些构造,比如作为方法的参数:
something.someMethod(['foo' : 'bar']);
Lists
列表用下面的格式来描述: [item1, item2, ...]
For example:
["Jim", "Bob", "Smith"]
Maps
Map用下面的格式来描述: [key1 : value1, key2: value2, ...]
For example:
["Foo" : "Bar", "Bar" : "Foo"]
Arrays
数组用下面的格式来描述: {item1, item2, ...}
For example:
{"Jim", "Bob", "Smith"}
foo.someMethod({1,2,3,4});
五、属性访问
if (user.manager != null) { return user.manager.name; } else { return null; }
当Map的key是String类型时,还可以使用特殊的方式来访问,如:user.foobar,也就是允许你把map本身看成一个虚拟的对象,来访问其属性
字符串作数组
为了能使用属性的索引(迭代也是如此),所有的字符串都可以看成是一个数组,在MVEL中你可以用下面的方式来获取一个字符串变量的第一个字符:
A literal is used to represent a fixed-value in the source of a particular script.
六、字面量literals
String literals
在脚本语言中,一段文字用来代表一个固定的值
字符串常量:
字符串常量可以用一对单引号或一对双引号来界定。如:
"This is a string literal"
'This is also string literal'
字符串中的特殊字符
\\
- Double escape allows rendering of single backslash in string.\n
- Newline\r
- Return\u####
- Unicode character (Example:\uAE00
)\###
- Octal character (Example:\73
)
数字常量
整数可以表示为十进制(基数为10),8进制(基数为8),或十六进制(基数为16)。
一个十进制数字,不从零开始(相对于8进制、16进制而言),可以表示任意数,如:125
125 // decimal
一个八进制数,以0为前缀,后面跟着0到7内的数字
0353 // octal
一个十六进制,以0X为前缀,后面可以跟着0-9,A-F范围内的数字
0xAFF0 // hex
浮点常量
A floating point number consists of a whole number and a factional part denoted by the point/period character, with an optional type suffix.
10.503 // a double
94.92d // a double
14.5f // a float
二进制常量
You can represent BigInteger
and BigDecimal
literals by using the suffixes B and I(uppercase is mandatory).
104.39484B // BigDecimal
8.4I // BigInteger
布尔常量
Boolean literals are represented by the reserved keywords true and false.
Null 常量
The null literal is denoted by the reserved keywords null or nil.
内部类
七、控制流程
if (var > 0) {
System.out.println("Greater than zero!");
}
else if (var == -1) {
System.out.println("Minus one!");
}
else {
System.out.println("Something else!");
}
var > 0 ? "Yes" : "No";
var > 0 ? "Yes" : (var == -1 ? "Minus One!" : "No")
count = 0;
foreach (name : people) {
count++;
System.out.println("Person #" + count + ":" + name);
} System.out.println("Total people: " + count);
foreach (el : str) {
System.out.print("[" + el + "]");
}
foreach (x : 9) {
System.out.print(x);
}
For Loop
MVEL 2.0 implements standard C for-loops:
for (int i =0; i < 100; i++) {
System.out.println(i);
}
Do While, Do Until
和java中的一样,MVEL也实现了Do While,Do Until,While和Until意义正好相反。
do {
x = something();
}
while (x != null);
... is semantically equivalent to ...
do {
x = something();
}
until (x == null);
While, Until
MVEL 2.0 implements standard while, with the addition of the inverse until.
while (isTrue()) {
doSomething();
}
... or ...
until (isFalse()) {
doSomething();
}
八、投影和交集
parentNames = (parent.name in users);
familyMembers = (name in (familyMembers in users));
九、赋值
MVEL允许你对表达式中的变量进行赋值,以便在运行时获取,或在表达式内部使用。因为MVEL是动态类型语言,所以你不必为了声明一个变量
而指定其类型。当然,你也可以选择指定。
str = "My String"; // valid
String str = "My String"; // valid 与java语言不同的是,当给一个指定类型的变量赋值时,MVEL会提供自动的类型转换(可行的话),如:
String num = 1;
assert num instanceof String && num == "1";
对于动态类型变量而言,你要想对其进行类型转换,你只需要将值转换成相应的类型既可:
num = (String) 1;
assert num instanceof String && num == "1";
Filters
(doSomeMethod() in listOfThings if $.shouldBeRun())
($ in fooList if $.name contains 'foobie')
(toUpperCase() in ["foo", "bar"]); // returns ["FOO", "BAR"]
(($ < 10) in [2,4,8,16,32]); // returns [true, true, true, false, false]
($ in [2,4,8,16,32] if $ < 10); // returns [2,4,8]
/**
* Sample MVEL 2.0 Script
* "Functional QuickSort"
* by: Christopher Michael Brock, Inspired by: Dhanji Prasanna
*/ import java.util.*; // the main quicksort algorithm
def quicksort(list) {
if (list.size() <= 1) {
list;
}
else {
pivot = list[0];
concat(quicksort(($ in list if $ < pivot)), pivot, quicksort(($ in list if $ > pivot)));
}
} // define method to concatenate lists.
def concat(list1, pivot, list2) {
concatList = new ArrayList(list1);
concatList.add(pivot);
concatList.addAll(list2);
concatList;
} // create a list to sort
list = [5,2,4,1,18,10,15,1,0]; // sort it!
quicksort(list)
十、函数
MVEL可以使用def或function关键字来定义本地函数。
函数必须是先声明后引用,唯一例外的是递归调用的时候。 1、简单示例
定义函数:
def hello() { System.out.println("Hello!"); }
定义了一个没有参数的函数hello.当调用该函数时会在控制台打印"Hello!". An MVEL-defined function works just like any regular method call, and resolution preference is to MVEL functions over base context methods. hello(); // calls function
2、传参和返回值 函数可以接收参数和返回一个值,看下面的例子:
def addTwo(a, b) {
a + b;
} 这个函数会接收两个参数(a和b),然后将这两个变量相加。因为MVEL遵循last-value-out原则,所以
结果将会被返回。因此,你可以这样来使用这个函数:
val = addTwo(5, 2);
assert val == 10;
当然,也可以使用return 关键字来强迫从程序内部返回一个函数值。
3、closures
MVEL支持closure,虽然,其功能与本地java函数没有任何关联。
// define a function that accepts a parameter
def someFunction(f_ptr) { f_ptr(); }
// define a var
var a = 10;
// pass the function a closure
someFunction(def { a * 10 });
十一、Lambda表达式
MVEL允许定义Lambda方法,如下所示:
threshold = def (x) { x >= 10 ? x : 0 };
result = cost + threshold(lowerBound);
上面的例子定义了一个Lambda,并将其赋值给变量"threshold".Lambda实质上就是一个用来给变量赋值的函数,也是closure
十二、拦截器
MVEL提供了在编译后的表达式里使用拦截器的功能,这对实现监听器或是在表达式内部触发一个外部事件特别有用。声明拦截器用的是@Syntax,
有点像java语言中的注解。拦截器的声明应该放在待封装的语句之前,它可以实现之前或之后的监听器,或二者都实现。例如: @Intercept
foreach (item : fooItems) {
total += fooItems.price;
}
在这个特殊的句子里,拦截器封装了整个的foreach块,因此,如果拦截器实现了之后的监听器,则当foreach循环结束后,拦截动作将被触发。 1、拦截器接口org.mvel.intergration.Interceptor public interface Interceptor {
public int doBefore(ASTNode node, VariableResolverFactory factory);
public int doAfter(Object exitStackValue, ASTNode node, VariableResolverFactory factory);
}
拦截器接口提供了两个待实现的方法:doBefore和doAfter,下面我们来看一下MVEL运行时传递给这两个方法的参数的含义 2、doBefore
在执行封装的命令前会执行doBefore方法。
org.mvel.ASTNode::node
ASTNode句柄是 拦截器内部ASTNode 的一个引用,可以用来获取实际编译后的代码的信息。
org.mvel.integration.VariableResolverFactory::factory
变量分析器工厂提供表达式内当前范围内变量的访问权限。
3、doAfter
在执行完封装的指令后执行doAfter方法
java.lang.Object::exitStackValue
doAfter方法虽是在语句执行后执行,但却不是在帧结束前。因此,操作结束时留在栈中的任何数据都仍然存在,而且能被拦截器访问。例如:
@Intercept cost += value;
这是一个比较特殊的句子,cost的原值一直保存在栈中,直到整个帧执行完毕,因此,这个值在调用doAfter方法时可以通过exitStackValue访问到。
org.mvel.ASTNode::node
这是传递到doBefore方法中的同一个AST 元素,更多细节参考doBefore方法。
org.mvel.intergration.VariableResolverFactory::factory
同doBefore方法
4、编译器中使用拦截器
为了能是拦截器连到表达式中,必须在编译表达式之前提供拦截器,因此有一点需要注意,拦截器可能不用于MVEL解释器。
拦截器是储存在map里提供给编译器的,map中的键为拦截器的名称,值为拦截器实例。如:
// Create a new ParserContext
ParserContext context = new ParserContext();
Map<String, Interceptor> myInterceptors = new HashMap<String, Interceptor>();
// Create a simple interceptor.
Interceptor myInterceptor = new Interceptor() {
public int doBefore(ASTNode node, VariableResolverFactory factory) {
System.out.println("BEFORE!");
} public int doAfter((Object value, ASTNode node, VariableResolverFactory factory) {
System.out.println("AFTER!");
}
}; // Now add the interceptor to the map.
myInterceptors.put("Foo", myInterceptor); // Add the interceptors map to the parser context.
context.setInterceptors(myInterceptors); // Compile the expression.
Serializable compiledExpression = MVEL.compileExpression(expression, context); 十四、数据类型 MVEL是一种有静态类型的动态类型语言。大部分MVEL使用者都比较倾向于用动态类型,因为它非常简单易用。如: a = 10; // declare a variable 'a'
b = 15; // declare a variable 'b'; a + b; 1、动态类型与强制转换 像MVEL这种直接与java对象(静态类型)打交道的语言,最重要的一个方面就是强制类型转换。因为MVEL不能对一个java.lang.String对象和一个 java.lang.Integer对象进行数学运算,所以就必须把其中一个的类型转换成另一个的类型。 2、性能考虑
在你的应用中集成一个像MVEL这样的东西,性能考虑是必须的。对于重量级程序加载,强制类型转换超负荷等可以通过缓存和优化器(仅用于预编译
的表达式)来解决。然而,并不是所有的强制类型转换都可以忽略不管,关键要看它是在做什么。 比如,当一个String类型的变量在运行中要看成一个整形变量时,要阻止运行时将字符串转换成整型简直是不可能的,像这种情况,一定要考虑其性能。 3、方法调用
调用方法是强制转换的最重要的一个方面。从根本上讲,你可以直接调用,而无需关心参数是什么。解释器或编译器会分析方法的参数类型,然后确定
要进行哪一种强制转换,如果是重载的方法,它会选择与输入类型最接近的那个方法进行调用,以尽可能的避免强制转换。 4、数组 数组是强制类型转换中最有趣的一个方面,因为MVEL缺省使用无类型数组(也就是说任何情况下都是Object[]),只有当遇到类型冲突时,才会尝试将 整个数组转换成所需的类型,比如在方法调用传参时。 示例: myArray = {1,2,3}; // pass to method that accepts String[]
myObject.someMethod(myArray); 在这个例子里,somMethod方法接收字符数组,这在MVEL中不会出错,相反,MVEL会将myArray转换成字符数组。 5、静态类型 静态类型与java类似,只不过默认情况下仍然会进行强制转换。 int num = 10; 这个句子声明了一个整型变量num,这时,MVEL运行时会强制转换类型。比如,声明后赋值一个不合适类型的数据,结果就会出现异常。 num = new HashMap(); // will throw an incompatible typing exception. 但如果是一个可以进行强制类型转换的值时,MVEL就会进行强制转换。 num = "100"; // will work -- parses String to an integer.
6、严格类型 严格类型是编译器的一种可选模式,在这种模式下,所有的类型都必须限定,不管是声明时还是在引用时。 启动严格模式: 当编译一个表达式时,可以通过ParserContext设置setStrictTypeEnforcement(true)将编译器设置成严格模式。 严格类型通过表达式内的具体类型声明或提前告诉转换器确定的类型来完成。例如: ExpressionCompiler compiler = new ExpressionCompiler(expr); ParserContext context = new ParserContext();
context.setStrictTypeEnforcement(true); context.addInput("message", Message.class);
context.addInput("person", Person.class); compiler.compile(context);
在这个例子中我们通知编译器表达式将接收两个外部输入:message 和 person 及它们的类型。这就使得编译器可以在编译时确定某一 个调用是否是安全的,从而防止了运行时的错误。 7、强类型 强类型是MVEL2.0新引入的概念。强类型模式要求所有的变量必须是限定的类型,从这一点上它与严格类型不同。差别在于严格模式只是在编译时 限定属性和方法调用的类型。 十五、Shell 通过交互式的Shell,你可以直接与MVEL打交道,去探究MVEL的特性。 1、运行Shell 只需运行MVEL的分布式jar包既可运行Shell:java -jar mvel2-2.0.jar
或者,你也可以在你喜欢的IDE中通过配置一个该类的运行环境来运行。 十六、FAQ 1、为什么不能使用.class的引用?
MVEL没有像java中的用来执行类型文件的.class标识符,其实它本身就没有class文件,而只需要通过其名称就可以引用这个类。比如,一个方法
接收一个Class类型作为参数,你可以这样来调用: // MVEL
someMethod(String); // Java-equivalent
someMethod(String.class);
事实上,MVEL将.class视作一个普通的bean属性,因此,如果使用String。class,那返回值就会是指向java.lang.Class本身的一个
java.lang.Class 的实例,因此就相当于在java中使用String.class.getClass() . 原理是这样的,MVEL使用动态类型系统,这样类型就被当作普通的变量来看待,而不是像java中限定类文件。所以,MVEL允许class类型作为 一个普通变量来引用,而不像java。 十七、为什么不能用object.class.name的格式? 这是MVEL的一个限制,可能会在将来的某个版本中标记出来,但bean属性不支持对Class的引用。并不是说不能调用Class的方法,你必须使用 限定的方法,像: someVar.class.getName(); // Yes!
someVar.class.name; // No! someVar.getClass().getName() // Yes!
someVar.getClass().name // No!
这一规定完全限制了java.lang.Class仅可用做某个变量的属性,并限制了MVEL处理类的引用的方式。
https://github.com/imona/tutorial/wiki/MVEL-Guide
http://blog.csdn.net/y461517142/article/details/17926055
mvel语法指南[翻译]的更多相关文章
- scons用户指南翻译(附gcc/g++参数详解)
scons用户指南 翻译 http://blog.csdn.net/andyelvis/article/category/948141 官网文档 http://www.scons.org/docume ...
- Protobuf3 语法指南
目录 [−] 定义一个消息类型 指定字段类型 分配标识号 指定字段规则 添加更多消息类型 添加注释 保留标识符(Reserved) 从.proto文件生成了什么? 标量数值类型 默认值 枚举 使用其他 ...
- ProtoBuf3语法指南(Protocol Buffers)_下
0.说明 ProtoBuf3语法指南, 又称为proto3, 是谷歌的Protocol Buffers第3个版本. 本文基于官方英文版本翻译, 加上了自己的理解少量修改, 一共分为上下两部分. 1.A ...
- ProtoBuf3语法指南(Protocol Buffers)_上
0.说明 ProtoBuf3语法指南, 又称为proto3, 是谷歌的Protocol Buffers第3个版本. 本文基于官方英文版本翻译, 加上了自己的理解少量修改, 一共分为上下两部分. 1.序 ...
- Markdown编辑器语法指南2
人的一切痛苦, 本质上都是对自己的无能的愤怒. --王小波 1 Markdown编辑器的基本用法 1.1 代码 如果你只想高亮语句中的某个函数名或关键字,可以使用 `function_name()` ...
- Markdown语法指南
1.背景 个人比较喜欢用Markdonw写东西,比如写博客随笔,写有道云笔记等,但有的时候会突然忘记某个具体语法怎么写了,如插入图片.插入链接.表格等,那干脆把这个语法简单地总结一下,也方便日后快速查 ...
- protobuf语法指南
遇到proto编译问问,看看proto语法,记录一下 protobuf3 语法指南 http://colobu.com/2017/03/16/Protobuf3-language-guide/ htt ...
- gRPC-Protocol语法指南
语法指南 (proto3) Defining A Message Type Scalar Value Types Default Values Enumerations Using Other Mes ...
- 一致性(ECMAScript语法标准翻译)
Conformance A conforming implementation of ECMAScript must provide and support all the types, values ...
随机推荐
- Ansible--Ansible之Playbook
Ansible之Playbook Playbook介绍 playbook参考文档 Playbook与ad-hoc相比,是一种完全不同的运用ansible的方式,类似与saltstack的state状态 ...
- CSS怎么隐藏滚动条(三种方法)
xhtml中隐藏滚动条在用ie6浏览有框架的xhtml页面的时候,默认会水平和垂直滚动条会一起出现,这是ie6的一个bug,在firefox上是正常的,出现的原因是其对XHTML 1.0 transi ...
- android studio学习----打包
Gradle打包APP签名 默认情况下,debug被配置成使用一个debug keystory.debug keystory使用了默认的密码和默认key及默认的key密码.debug构建类型会自动使用 ...
- Golang Web应用 创建docker镜像笔记(win 平台)
记录的是 本地编译好了再创建容器镜像的方法 ,这样子生成的镜像文件比较小,方便分发部署 win 平台需要设置golang交叉编译 生成linux可执行文件 CMD下: Set GOOS="l ...
- 【故障处理】imp-00051,imp-00008
[故障处理]imp-00051,imp-00008 1.1 BLOG文档结构图 1.2 故障分析及解决过程 imp导入报错: IMP-00051: Direct path exported dum ...
- 【Python】生成器
生成器是一种特殊的迭代器 # 斐波那契数列 10 def create_num(all_num): a, b = 0, 1 current_num = 0 while current_num < ...
- Java 堆内存 新生代 (转)
Java 中的堆是 JVM 所管理的最大的一块内存空间,主要用于存放各种类的实例对象.在 Java 中,堆被划分成两个不同的区域:新生代 ( Young ).老年代 ( Old ).新生代 ( You ...
- 四川第十届省赛 A.Angel Beats bitset
四川第十届省赛 A.Angel Beats bitset 题目链接 题解参考:http://www.cnblogs.com/Aragaki/p/9142250.html 考虑用bitset来维护对于所 ...
- Beta 冲刺随笔汇总
作业要求 这个作业属于哪个课程 软件工程1916-W(福州大学) 这个作业要求在哪里 项目Beta冲刺(团队) 团队名称 基于云的胜利冲锋队 作业目标 汇总随笔 团队信息 团队名称:基于云的胜利冲锋队 ...
- 项目Beta冲刺(团队) —— 凡事预则立
1.讨论组长是否重选的议题和结论 讨论: 我们采取匿名群投票的方式进行 投票结果如下: 成员共7人 投票7人 投票率100% 结果有效 结论: 不需要重选组长 2.下一阶段需要改进完善的功能 完善游戏 ...