Aviator 表達式求值引擎

1.簡介

Aviator是一個高性能、輕量級的 java 語言實現的表達式求值引擎, 主要用於各種表達式的動態求值。現在已經有很多開源可用的 java 表達式求值引擎,爲什麼還需要 Avaitor 呢?
Aviator的設計目標是輕量級和高性能,相比於Groovy、JRuby的笨重, Aviator非常小, 加上依賴包也才 537K,不算依賴包的話只有 70K; 當然, Aviator的語法是受限的, 它不是一門完整的語言, 而只是語言的一小部分集合。
其次, Aviator的實現思路與其他輕量級的求值器很不相同, 其他求值器一般都是通過解釋的方式運行, 而Aviator則是直接將表達式編譯成 JVM 字節碼, 交給 JVM 去執行。簡單來說, Aviator的定位是介於 Groovy 這樣的重量級腳本語言和 IKExpression 這樣的輕量級表達式引擎之間。

2.特性

Aviator的特性:

  • 支持絕大多數運算操作符,包括算術操作符、關係運算符、邏輯操作符、位運算符、正則匹配操作符(=~)、三元表達式(? : );
  • 支持操作符優先級和括號強制設定優先級;
  • 邏輯運算符支持短路運算;
  • 支持豐富類型,例如nil、整數和浮點數、字符串、正則表達式、日期、變量等,支持自動類型轉換;
  • 支持傳入變量,支持類似a.b.c的嵌套變量訪問;
  • 內置一套強大的常用函數庫;
  • 可自定義函數,易於擴展;
  • 可重載操作符;
  • 支持大數運算(BigInteger)和高精度運算(BigDecimal);
  • 性能優秀。

Aviator的限制:

  • 沒有if else、do while等語句,沒有賦值語句,僅支持邏輯表達式、算術表達式、三元表達式和正則匹配。
  • 無法自定義運算符,自定義函數有侷限性

3.依賴

Aviator依賴了commons-beanutils, 使用Aviator可以添加下面的maven依賴:

<dependency>
      <groupId>com.googlecode.aviator</groupId>
      <artifactId>aviator</artifactId>
      <version>{version}</version>
 </dependency>

從 3.2.0 版本開始, Aviator 僅支持 JDK 7 及其以上版本。 JDK 6 請使用 3.1.1 這個穩定版本。

4.使用手冊

  1. 執行表達式
    Aviator的使用都是集中通過com.googlecode.aviator.AviatorEvaluator這個入口類來處理, 最簡單的例子, 執行一個計算1+2+3的表達式:
val result = AviatorEvaluator.execute("1+2+3")
println(result)     //6

如果開啓了 ALWAYS_PARSE_FLOATING_POINT_NUMBER_INTO_DECIMAL 選項,那麼在表達式中出現的浮點數都將解析爲 BigDecimal,這是爲了方便一些用戶要求高精度的計算,又不想額外地給浮點數加上 M 後綴標記爲 BigDecimal:

AviatorEvaluator.setOption(Options.ALWAYS_PARSE_FLOATING_POINT_NUMBER_INTO_DECIMAL, true)
  1. 多行表達式
    從 4.0.0 開始, aviator支持以分號 ; 隔開的多行表達式,對於多行表達式求值的結果將是最後一個表達式的結果,例如
val result = AviatorEvaluator.execute("println('hello world'); 1+2+3 ; 100-1")
println(result) 
//輸出結果:
//hello world
//99

表達式的結果將是最後一個表達式 100-1,也就是 99,但是中間的表達式也將執行,包括打印 hello world。通過在表達式求值過程中加入 println打印,可以方便調試,也可以通過 Options.TRACE_EVAL來跟蹤執行過程,參見後續章節。

  1. 求值器多實例
    AviatorEvaluator是一個全局靜態實例,但是很多場景下,你可能想爲不同的場景提供一個不同的求值器實例,包括不同的選項配置和自定義函數列表等,那麼從 4.0.0開始, Aviator提供了多實例的求值器支持:
val instance = AviatorEvaluator.newInstance
//接下來使用 instance,幾乎跟 AviatorEvaluator 沒有不同,只是換成了實例方法
  1. 使用變量
    下面的例子演示了怎麼向表達式傳入變量值, 表達式中的world是一個變量, 默認爲null, 通過傳入Map<String,Object>的變量綁定環境, 將world設置爲“world”。 env 的key是變量名, value是變量的值。
val world = "world"
val env = new util.HashMap[String,Object]()
env.put("world",world)
val result =AviatorEvaluator.execute(" 'hello ' + world ",env)
println(result)        //  hello world

'hello ‘是一個Aviator的String, Aviator的String是任何用單引號或者雙引號括起來的字符序列, String可以比較大小(基於unicode順序), 可以參與正則匹配, 可以與任何對象相加, 任何對象與String相加結果爲String。 String中也可以有轉義字符,如\n、\、’ 等。

AviatorEvaluator.execute(" 'a\"b' ")                  // 字符串 a"b
AviatorEvaluator.execute(" \"a\'b\" ")                // 字符串 a'b
AviatorEvaluator.execute(" 'hello ' + 3 ")              // 字符串 hello 3
AviatorEvaluator.execute(" 'hello '+ unknow ")         // 字符串 hello null
  1. exec 方法
    Aviator 2.2 開始新增加一個exec方法, 可以更方便地傳入變量並執行, 而不需要構造env這個map了:
val value = "world"
AviatorEvaluator.exec("'hello' + value",value)        //  hello world
  1. 調用函數
    Aviator 支持函數調用, 函數調用的風格類似 lua, 下面的例子獲取字符串的長度:
AviatorEvaluator.execute("string.length('hello')") 

string.length(‘hello’)是一個函數調用, string.length是一個函數, 'hello’是調用的參數。
再用string.substring來截取字符串:

AviatorEvaluator.execute("string.contains(\"test\", string.substring('hello', 1, 2))") // true

通過string.substring(‘hello’, 1, 2)獲取字符串’e’, 然後通過函數string.contains判斷e是否在’test’中。可以看到, 函數可以嵌套調用。

  1. 自定義函數
    Aviator除了內置的函數之外,還允許用戶自定義函數,只要實現com.googlecode.aviator.runtime.type.AviatorFunction接口, 並註冊到AviatorEvaluator即可使用. AviatorFunction接口十分龐大, 通常來說你並不需要實現所有的方法, 只要根據你的方法的參數個數, 繼承AbstractFunction類並override相應方法即可。
object test {
  def main(args: Array[String]): Unit = {
    AviatorEvaluator.addFunction(new AddFunction)
    System.out.println(AviatorEvaluator.execute("add(1, 2)")) // 3.0
    System.out.println(AviatorEvaluator.execute("add(add(1, 2), 100)")) // 103.0
  }
}
class AddFunction extends AbstractFunction{
  override def call(env: java.util.Map[String, Object], arg1: AviatorObject, arg2: AviatorObject): AviatorObject = {
    val left = FunctionUtils.getNumberValue(arg1, env)
    val right = FunctionUtils.getNumberValue(arg2, env)
    new AviatorDouble(left.doubleValue + right.doubleValue)
  }

  def getName = "add"
}

註冊函數通過AviatorEvaluator.addFunction方法, 移除可以通過removeFunction。另外, FunctionUtils 提供了一些方便參數類型轉換的方法。

如果你的參數個數不確定,可以繼承 AbstractVariadicFunction 類,只要實現其中的 variadicCall 方法即可,比如我們實現一個找到第一個參數不爲 null 的函數:

object test {
  def main(args: Array[String]): Unit = {
    AviatorEvaluator.addFunction(new GetFirstNonNullFunction)
    System.out.println(AviatorEvaluator.execute("getFirstNonNull(1)")) // 1
    System.out.println(AviatorEvaluator.execute("getFirstNonNull(1,2,3,4,nil,5)")) // 1
    System.out.println(AviatorEvaluator.execute("getFirstNonNull(a,b,c,d)")) // null
  }
}
class GetFirstNonNullFunction extends AbstractVariadicFunction {
  override def variadicCall(env: util.Map[String, AnyRef], args: AviatorObject*): AviatorObject = {
    if (args != null) for (arg <- args) {
      if (arg.getValue(env) != null) return arg
    }
    new AviatorString(null)
  }

  override def getName = "getFirstNonNull"

}

當然,同時你仍然覆寫特定的 call 方法來自定義實現。
自定義函數在 4.0.0 之後也可以通過 lambda 來定義:

AviatorEvaluator.defineFunction("add", "lambda (x,y) -> x + y end")
AviatorEvaluator.exec("add(1,2)")    //3
  1. 函數加載器
    從 4.0.0 開始,Aviator 還支持 FunctionLoader接口,可以用於自定義函數加載器:
class function extends FunctionLoader{
  /**
    * Invoked when function not found
    *
    * @param name function name
    */
  override def onFunctionNotFound(name: String): AviatorFunction = ???
}

用戶可以自主實現函數加載器,當函數不能從當前求值器中找到的時候,將調用 loader 的onFunctionNotFound 方法進行查找。自定義的加載器,通過 AviatorEvaluator.addFunctionLoader(loader)註冊,可以註冊多個加載器,加載順序將按照添加順序進行查找,其中任何一個找到,都將中斷查找過程。

  1. 重載運算符
    Aviator 支持的運算符參見操作符一節。部分用戶可能有重載這些內置運算符的需求,例如在 Excel 裏, & 不是位運算,而是字符串連接符,那麼你可以通過 3.3.0 版本支持的運算符重載來實現:
AviatorEvaluator.addOpFunction(OperatorType.BIT_AND, new AbstractFunction() {
      override def call(env: util.Map[String, Object], arg1: AviatorObject, arg2: AviatorObject) = new AviatorString(arg1.getValue(env).toString + arg2.getValue(env).toString)

      override def getName = "&"
    })

AviatorEvaluator.addOpFunction(opType, func) 就可以重載指定的運算符,重載後運行即可看到:

val map = new util.HashMap[String,Object]()
map.put("a","4")
val result = AviatorEvaluator.execute("a&3", map)
println(result)      //43
val map1 = new util.HashMap[String,Object]()
map1.put("a","hello")
val result1 =  AviatorEvaluator.execute("a&' world'", map1)
println(result1)    //hello world

請注意,運算符重載使用不當,一定程度上會帶來混亂,並且有一定的性能損失,請慎重使用。

  1. 編譯表達式
    上面提到的例子都是直接執行表達式, 事實上 Aviator 背後都幫你做了編譯並執行的工作。 你可以自己先編譯表達式, 返回一個編譯的結果, 然後傳入不同的env來複用編譯結果, 提高性能, 這是更推薦的使用方式:
val expression = "a-(b-c)>100"
// 編譯表達式
val compiledExp = AviatorEvaluator.compile(expression)
val env = new util.HashMap[String,Object]()
env.put("a", 100.3.asInstanceOf[Object])
env.put("b", new Integer(45))
env.put("c", (-199.100).asInstanceOf[Object])
// 執行表達式
val result = compiledExp.execute(env).asInstanceOf[Boolean]
println(result) // false

通過compile方法可以將表達式編譯成Expression的中間對象, 當要執行表達式的時候傳入env並調用Expression的execute方法即可。 表達式中使用了括號來強制優先級, 這個例子還使用了>用於比較數值大小, 比較運算符!=、==、>、>=、<、<=不僅可以用於數值, 也可以用於String、Pattern、Boolean等等, 甚至是任何用戶傳入的兩個都實現了java.lang.Comparable接口的對象之間。

編譯後的結果你可以自己緩存, 也可以交給 Aviator 幫你緩存, AviatorEvaluator內部有一個全局的緩存池, 如果你決定緩存編譯結果, 可以通過:

public static Expression compile(final String expression, final boolean cached)

將cached設置爲true即可, 那麼下次編譯同一個表達式的時候將直接返回上一次編譯的結果。
使緩存失效通過:

public static void invalidateCache(String expression)
  1. 訪問數組和集合
    可以通過中括號去訪問數組和java.util.List對象, 可以通過map.key訪問java.util.Map中key對應的value, 一個例子:
val list = new util.ArrayList[String]
list.add("hello")
list.add(" world")
val array = new Array[Int](3)
array(0) = 0
array(1) = 1
array(2) = 3
val map = new util.HashMap[String,Object]()
map.put("date", new Date())
val env = new util.HashMap[String,Object]()
env.put("list", list)
env.put("array", array)
env.put("mmap", map)
println(AviatorEvaluator.execute("list[0]+list[1]", env)) // hello world

println(AviatorEvaluator.execute("'array[0]+array[1]+array[2]=' + (array[0]+array[1]+array[2])", env)) // array[0]+array[1]+array[2]=4

println(AviatorEvaluator.execute("'today is ' + mmap.date ", env)) // today is Tue Mar 19 11:42:51 CST 2019

如果函數調用或者括號表達式結果是一個數組或者List,你同樣可以可以通過 [index] 訪問:

println(AviatorEvaluator.exec("string.split(s,',')[0]", "a,b,c,d"))    //a
  1. 三元操作符
    Aviator 不提供if else語句, 但是提供了三元操作符?:用於條件判斷,使用上與 java 沒有什麼不同:
println(AviatorEvaluator.exec("a>0? 'yes':'no'", new Integer(1))) // yes

Aviator 的三元表達式對於兩個分支的結果類型並不要求一致,可以是任何類型,這一點與 java 不同。

  1. 正則表達式匹配
    Aviator 支持類 Ruby 和 Perl 風格的表達式匹配運算,通過=~操作符, 如下面這個例子匹配 email 並提取用戶名返回:
val email = "[email protected]"
val env = new util.HashMap[String,Object]()
env.put("email", email)
val username = AviatorEvaluator.execute("email=~/([\\w0-8]+)@\\w+[\\.\\w+]+/ ? $1 : 'unknow' ", env).asInstanceOf[String]
println(username) // killme2008

email與正則表達式/([\w0-8]+@\w+[\.\w+]+)/通過=~操作符來匹配,結果爲一個 Boolean 類 型, 因此可以用於三元表達式判斷,匹配成功的時候返回$1,指代正則表達式的分組 1,也就是用戶名,否則返回unknown。
Aviator 在表達式級別支持正則表達式,通過//括起來的字符序列構成一個正則表達式,正則表達式可以用於匹配(作爲=~的右操作數)、比較大小。但是匹配僅能與字符串進行匹配。匹配成功後, Aviator 會自動將匹配成功的捕獲分組(capturing groups) 放入 env ${num}的變量中,其中$0 指代整個匹配的字符串,而$1表示第一個分組,$2表示第二個分組以此類推。
請注意,分組捕獲放入 env 是默認開啓的,因此如果傳入的 env 不是線程安全並且被併發使用,可能存在線程安全的隱患。關閉分組匹配,可以通過 AviatorEvaluator.setOption(Options.PUT_CAPTURING_GROUPS_INTO_ENV, false); 來關閉,對性能有稍許好處。
Aviator 的正則表達式規則跟 Java 完全一樣,因爲內部其實就是使用java.util.regex.Pattern做編譯的。

  1. 變量的語法糖
    Aviator 有個方便用戶使用變量的語法糖, 當你要訪問變量a中的某個屬性b, 那麼你可以通過a.b訪問到, 更進一步, a.b.c將訪問變量a的b屬性中的c屬性值, 推廣開來也就是說 Aviator 可以將變量聲明爲嵌套訪問的形式。
    TestAviator類符合JavaBean規範, 並且是 public 的,我們就可以使用語法糖:
object test { 

  def main(args: Array[String]): Unit = {
    val foo = new Foo(100, 3.14f, new Date())
    val env = new util.HashMap[String,Object]()
    env.put("foo", foo)
    println(AviatorEvaluator.execute("'foo.i = '+foo.i", env)) // foo.i = 100

    println(AviatorEvaluator.execute("'foo.f = '+foo.f", env)) // foo.f = 3.14

    println(AviatorEvaluator.execute("'foo.date.year = '+(foo.date.year+1900)", env)) // foo.date.year = 2019

  }
}

class Foo(var i: Int, var f: Float, var date: Date) {

  def getI: Int = i

  def setI(i: Int): Unit = {
    this.i = i
  }

  def getF: Float = f

  def setF(f: Float): Unit = {
    this.f = f
  }

  def getDate: Date = date

  def setDate(date: Date): Unit = {
    this.date = date
  }
}
  1. nil 對象
    nil是 Aviator 內置的常量,類似 java 中的null,表示空的值。nil跟null不同的在於,在 java 中null只能使用在==、!=的比較運算符,而nil還可以使用>、>=、<、<=等比較運算符。 Aviator 規定,任何對象都比nil大除了nil本身。用戶傳入的變量如果爲null,將自動以nil替代。
AviatorEvaluator.execute("nil == nil");   //true
AviatorEvaluator.execute(" 3> nil");      //true
AviatorEvaluator.execute(" true!= nil");  //true
AviatorEvaluator.execute(" ' '>nil ");    //true
AviatorEvaluator.execute(" a==nil ");     //true, a 是 null

nil與String相加的時候,跟 java 一樣顯示爲 null

  1. 日期比較
    Aviator 並不支持日期類型,如果要比較日期,你需要將日期寫字符串的形式,並且要求是形如 “yyyy-MM-dd HH:mm:ss:SS”的字符串,否則都將報錯。 字符串跟java.util.Date比較的時候將自動轉換爲Date對象進行比較:
val env = new util.HashMap[String,Object]()
val date = new Date()
val dateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SS").format(date)
env.put("date", date)
env.put("dateStr", dateStr)
var result = AviatorEvaluator.execute("date==dateStr", env).asInstanceOf[Boolean]
println(result) // true
result = AviatorEvaluator.execute("date > '2010-12-20 00:00:00:00' ", env).asInstanceOf[Boolean]
println(result)// true
result = AviatorEvaluator.execute("date < '2200-12-20 00:00:00:00' ", env).asInstanceOf[Boolean]
println(result)// true
result = AviatorEvaluator.execute("date==date ", env).asInstanceOf[Boolean]
println(result)// true

也就是說String除了能跟String比較之外,還能跟nil和java.util.Date對象比較。

  1. 大數計算和精度
    從 2.3.0 版本開始,aviator 開始支持大數字計算和特定精度的計算, 本質上就是支持java.math.BigInteger和java.math.BigDecimal兩種類型, 這兩種類型在 aviator 中簡稱爲big int和decimal類型。 類似99999999999999999999999999999999這樣的數字在 Java 語言裏是沒辦法編譯通過 的, 因爲它超過了Long類型的範圍, 只能用BigInteger來封裝。但是 aviator 通過包裝,可以直接支持這種大整數的計算,例如:
println(AviatorEvaluator.execute("99999999999999999999999999999999 + 99999999999999999999999999999999"))
//結果:199999999999999999999999999999998
  1. 字面量表示
    big int和decimal的表示與其他數字不同,兩條規則:
    以大寫字母N爲後綴的整數都被認爲是big int,如1N,2N,9999999999999999999999N等, 都是big int類型。
    超過long範圍的整數字面量都將自動轉換爲big int類型。
    以大寫字母M爲後綴的數字都被認爲是decimal, 如1M,2.222M, 100000.9999M等, 都是decimal類型。
    用戶也可以通過變量傳入這兩種類型來參與計算。
    如果用戶覺的給浮點數添加 M 後綴比較繁瑣,也可以強制所有浮點數解析爲 BigDecimal,通過代碼開啓下列選項即可:
AviatorEvaluator.setOption(Options.ALWAYS_PARSE_FLOATING_POINT_NUMBER_INTO_DECIMAL, true)
  1. 運算
    big int和decimal的運算,跟其他數字類型long,double沒有什麼區別,操作符仍然是一樣的。 aviator重載了基本算術操作符來支持這兩種新類型:
var rt = AviatorEvaluator.exec("9223372036854775807100.356M * 2")
println(rt + " " + rt.getClass) // 18446744073709551614200.712 class java.math.BigDecimal
rt = AviatorEvaluator.exec("92233720368547758074+1000")
println(rt + " " + rt.getClass) // 92233720368547759074 class java.math.BigInteger
val a = new BigInteger(String.valueOf(Long.MaxValue) + String.valueOf(Long.MaxValue))
val b = new java.math.BigDecimal("3.2")
val c = new java.math.BigDecimal("9999.99999")
rt = AviatorEvaluator.exec("a+10000000000000000000", a)
println(rt + " " + rt.getClass) // 92233720368547758089223372036854775807 class java.math.BigInteger
rt = AviatorEvaluator.exec("b+c*2", b, c)
println(rt + " " + rt.getClass) // 20003.19998 class java.math.BigDecimal
rt = AviatorEvaluator.exec("a*b/c", a, b, c)
println(rt + " " + rt.getClass) // 2.951479054745007313280155218459508E+34 class java.math.BigDecimal
  1. 類型轉換和提升
    當big int或者decimal和其他類型的數字做運算的時候,按照long < big int < decimal < double的規則做提升, 也就是說運算的數字如果類型不一致, 結果的類型爲兩者之間更“高”的類型。例如:
    1 + 3N, 結果爲big int的4N
    1 + 3.1M,結果爲decimal的4.1M
    1N + 3.1M,結果爲decimal的 4.1M
    1.0 + 3N,結果爲double的4.0
    1.0 + 3.1M,結果爲double的4.1
    decimal 的計算精度
    Java 的java.math.BigDecimal通過java.math.MathContext支持特定精度的計算,任何涉及到金額的計算都應該使用decimal類型。
    默認 Aviator 的計算精度爲MathContext.DECIMAL128,你可以自定義精度, 通過:
AviatorEvaluator.setOption(Options.MATH_CONTEXT, MathContext.DECIMAL64)

即可設置,更多關於decimal的精度問題請看java.math.BigDecimal的 javadoc 文檔。

  1. 強大的 seq 庫
    aviator 擁有強大的操作集合和數組的 seq 庫。整個庫風格類似函數式編程中的高階函數。在 aviator 中, 數組以及java.util.Collection下的子類都稱爲seq,可以直接利用 seq 庫進行遍歷、過濾和聚合等操作。
    例如,假設我有個 list:
val env = new util.HashMap[String,Object]()
val list = new util.ArrayList[Integer]
list.add(3)
list.add(20)
list.add(10)
env.put("list", list)
var result = AviatorEvaluator.execute("count(list)", env)
println(result) // 3
result = AviatorEvaluator.execute("reduce(list,+,0)", env)
println(result) // 33
result = AviatorEvaluator.execute("filter(list,seq.gt(9))", env)
println(result) // [20, 10]
result = AviatorEvaluator.execute("include(list,10)", env)
println(result) // true
result = AviatorEvaluator.execute("sort(list)", env)
println(result) // [3, 10, 20]
AviatorEvaluator.execute("map(list,println)", env)

我們可以:
求長度: count(list)
求和: reduce(list,+,0), reduce函數接收三個參數,第一個是seq,第二個是聚合的函數,如+等,第三個是聚合的初始值
過濾: filter(list,seq.gt(9)), 過濾出list中所有大於9的元素並返回集合; seq.gt函數用於生成一個謂詞,表示大於某個值
判斷元素在不在集合裏: include(list,10)
排序: sort(list)
遍歷整個集合: map(list,println), map接受的第二個函數將作用於集合中的每個元素,這裏簡單地調用println打印每個元素
其他還有:
seq.some(list, pred) 當集合中只要有一個元素滿足謂詞函數 pred 返回 true,立即返回 true,否則爲 false。
seq.every(list, pred) 當集合裏的每個元素都滿足謂詞函數 pred 返回 true,則結果爲 true,否則返回 false。
seq.not_any(list, pred),當集合裏的每個元素都滿足謂詞函數 pred 返回 false,則結果爲 true,否則返回 false。
以及 seq.or(p1, p2, …) 和 seq.and(p1, p2, …) 用於組合 seq.gtseq.lt 等謂詞函數。

  1. 兩種運行模式
    默認 AviatorEvaluator 以執行速度優先:
AviatorEvaluator.setOption(Options.OPTIMIZE_LEVEL, AviatorEvaluator.EVAL)

你可以修改爲編譯速度優先,這樣不會做編譯優化:

AviatorEvaluator.setOption(Options.OPTIMIZE_LEVEL, AviatorEvaluator.COMPILE)
  1. 調試信息
    如果想查看每個表達式生成的字節碼,可以通過打開 Trace 選項:
AviatorEvaluator.setOption(Options.TRACE, true)

默認是打印到標準輸出,你可以改變輸出指向:

AviatorEvaluator.setTraceOutputStream(new FileOutputStream(new File("aviator.log")))

5.語法手冊

下面是 Aviator 詳細的語法規則定義。

數據類型

  • Number類型: 數字類型,支持四種類型,分別是long,double,java.math.BigInteger(簡稱 big int)和java.math.BigDecimal(簡 稱 decimal),規則如下:
    • 任何以大寫字母 N 結尾的整數都被認爲是 big int
    • 任何以大寫字母 M 結尾的數字都被認爲是 decimal
    • 其他的任何整數都將被轉換爲 Long
    • 其他任何浮點數都將被轉換爲 Double
    • 超過 long 範圍的整數字面量都將自動轉換爲 big int 類型、

其中 big int 和 decimal 是 2.3.0 版本開始引入的。數字還支持十六進制(以0x或者0X開頭的數字), 以及科學計數法,如1e-3等。 不支持其他進制。

  • String類型: 字符串類型,單引號或者雙引號括起來的文本串,如’hello world’, 變量如果傳入的是String或者Character也將轉爲String類型
  • Bool類型: 常量true和false,表示真值和假值,與 java 的Boolean.TRUE和Boolean.False對應
  • Pattern類型: 正則表達式, 以//括起來的字符串,如/\d+/,內部 實現爲java.util.Pattern
  • 變量類型: 與 Java 的變量命名規則相同,變量的值由用戶傳入
  • nil類型: 常量nil,類似 java 中的null,但是nil比較特殊,nil不僅可以參與==、!=的比較, 也可以參與>、>=、<、<=的比較,Aviator 規定任何類型都大於nil除了nil本身,nil==nil返回true。 用戶傳入的變量值如果爲null,那麼也將作爲nil處理,nil打印爲null

操作符

  • 算術運算符
    Aviator 支持常見的算術運算符,包括+ - * / %五個二元運算符,和一元運算符-(負)。其中- * / %和一元的-僅能作用於Number類型。
    +不僅能用於Number類型,還可以用於String的相加,或者字符串與其他對象的相加。
    Aviator 規定,任何類型與String相加,結果爲String。

  • 邏輯運算符
    Avaitor 的支持的邏輯運算符包括,一元否定運算符!,以及邏輯與的&&,邏輯或的||。邏輯運算符的操作數只能爲Boolean。
    &&和||都執行短路規則。

  • 關係運算符
    Aviator 支持的關係運算符包括<, <=, >, >=以及==和!= 。
    關係運算符可以作用於Number之間、String之間、Pattern之間、Boolean之間、變量之間以及其他類型與nil之間的關係比較, 不同類型除了nil之外不能相互比較。

  • 位運算符
    Aviator 支持所有的 Java 位運算符,包括&, |, ^, ~, >>, <<, >>>。

  • 匹配運算符
    匹配運算符=~用於String和Pattern的匹配,它的左操作數必須爲String,右操作數必須爲Pattern。 匹配成功後,Pattern的分組將存於變量$num,num爲分組索引。

  • 三元運算符
    Aviator 沒有提供if else語句,但是提供了三元運算符?:,形式爲bool ? exp1: exp2。 其中bool必須爲Boolean類型的表達式, 而exp1和exp2可以爲任何合法的 Aviator 表達式,並且不要求exp1和exp2返回的結果類型一致。

6.內置函數

完整的內置函數列表參見內置函數。
點擊此處

7.選項列表

AviatorEvaluator.setOption(opt, val) 支持定義求值器的行爲,完整的 Options 枚舉選項參見完整選項說明
點擊此處

8.JavaDoc

點擊此處

9.4.0功能詳解

點擊此處

10.參考鏈接

主頁
示例
官方指南

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章