学习总结录 学习总结录
首页
归档
分类
标签
  • Java基础
  • Java集合
  • MySQL
  • Redis
  • JVM
  • 多线程
  • 计算机网络
  • 操作系统
  • Spring
  • Kafka
  • Elasticsearch
  • Python
  • 面试专题
  • 案例实践
  • 工具使用
  • 项目搭建
  • 服务治理
  • ORM框架
  • 分布式组件
  • MiniSpring
  • 设计模式
  • 算法思想
  • 编码规范
友链
关于
GitHub (opens new window)
首页
归档
分类
标签
  • Java基础
  • Java集合
  • MySQL
  • Redis
  • JVM
  • 多线程
  • 计算机网络
  • 操作系统
  • Spring
  • Kafka
  • Elasticsearch
  • Python
  • 面试专题
  • 案例实践
  • 工具使用
  • 项目搭建
  • 服务治理
  • ORM框架
  • 分布式组件
  • MiniSpring
  • 设计模式
  • 算法思想
  • 编码规范
友链
关于
GitHub (opens new window)
  • 案例实践

  • 工具使用

    • MyBatisPlus
    • Linux
    • RabbitMQ
    • Elasticsearch
    • JWT
    • MongoDB
    • Redis
    • Git
    • Kafka
    • Docker
    • PromQL
    • AviatorScript
      • 一、介绍
      • 二、原理和特点
      • 三、Hello World
        • 1、Java使用
        • 2、编译和执行
        • 2.1、AviatorScript引擎
        • 2.2、编译脚本文件
        • 2.3、编译文本文件
        • 2.4、执行
        • 2.5、语法校验
      • 四、基本类型和语法
        • 1、基本类型及运算
        • 1.1、整数
        • 1.2、大整数
        • 1.3、浮点数
        • 1.4、高精度计算
        • 1.5、数字类型转换
        • 1.6、字符串
        • 1.7、布尔类型
        • 1.8、逻辑运算
        • 1.9、三元运算符
        • 1.10、正则表达式
        • 2、运算符
        • 2.1、幂运算
        • 2.2、位运算
        • 3、注释
        • 4、变量
        • 4.1、定义和赋值
        • 4.2、动态类型
        • 4.3、nil
        • 4.4、传入变量
        • 4.5、引用变量
        • 4.6、访问Java静态变量
        • 5、作用域
        • 5.1、let语句
        • 5.2、嵌套作用域
        • 6、多行表达式和return
        • 6.1、多行表达式
        • 6.2、return
        • 7、创建对象
        • 8、use语句引用Java类
      • 五、条件语句
      • 六、循环语句
        • 1、普通循环
        • 2、集合遍历
        • 3、索引和KV遍历
        • 4、continue/break/return
        • 5、while
      • 七、Statement语句和值
        • 1、条件语句的值
        • 2、循环语句的值
        • 3、块(Block)的值
      • 八、异常处理
      • 九、函数和闭包
        • 1、函数定义和调用
        • 2、函数返回值
        • 3、函数重载
        • 4、不定参数
        • 5、匿名函数
        • 6、闭包
      • 十、数组
        • 1、创建数组
        • 2、创建指定类型数组
        • 3、创建空数组
        • 3.1、一维数组
        • 3.2、多维数组
        • 4、遍历数组
      • 十一、集合
        • 1、List
        • 2、Map
        • 3、Set
        • 4、集合操作
        • 4.1、添加元素
        • 4.2、访问元素
        • 4.3、判断元素是否存在
        • 4.4、遍历集合
        • 4.5、删除元素
      • 参考
    • Java 17
    • Groovy
  • 项目搭建

  • 服务治理

  • ORM框架

  • MiniSpring

  • 案例归档
  • 工具使用
旭日
2023-05-29
目录
一、介绍
二、原理和特点
三、Hello World
1、Java使用
2、编译和执行
2.1、AviatorScript引擎
2.2、编译脚本文件
2.3、编译文本文件
2.4、执行
2.5、语法校验
四、基本类型和语法
1、基本类型及运算
1.1、整数
1.2、大整数
1.3、浮点数
1.4、高精度计算
1.5、数字类型转换
1.6、字符串
1.7、布尔类型
1.8、逻辑运算
1.9、三元运算符
1.10、正则表达式
2、运算符
2.1、幂运算
2.2、位运算
3、注释
4、变量
4.1、定义和赋值
4.2、动态类型
4.3、nil
4.4、传入变量
4.5、引用变量
4.6、访问Java静态变量
5、作用域
5.1、let语句
5.2、嵌套作用域
6、多行表达式和return
6.1、多行表达式
6.2、return
7、创建对象
8、use语句引用Java类
五、条件语句
六、循环语句
1、普通循环
2、集合遍历
3、索引和KV遍历
4、continue/break/return
5、while
七、Statement语句和值
1、条件语句的值
2、循环语句的值
3、块(Block)的值
八、异常处理
九、函数和闭包
1、函数定义和调用
2、函数返回值
3、函数重载
4、不定参数
5、匿名函数
6、闭包
十、数组
1、创建数组
2、创建指定类型数组
3、创建空数组
3.1、一维数组
3.2、多维数组
4、遍历数组
十一、集合
1、List
2、Map
3、Set
4、集合操作
4.1、添加元素
4.2、访问元素
4.3、判断元素是否存在
4.4、遍历集合
4.5、删除元素
参考

AviatorScript

# 一、介绍

Aviator是一个高性能、轻量级的java语言实现的表达式求值引擎,主要用于各种表达式的动态求值。Aviator相比于Groovy、JRuby的笨重,Aviator非常轻量。

# 二、原理和特点

  • 高性能:Aviator 的基本过程是将表达式直接翻译成对应的 java 字节码执行,整个过程最多扫两趟(开启执行优先模式,如果是编译优先模式下就一趟),这样就保证了它的性能超越绝大部分解释性的表达式引擎

  • 轻量级:除了依赖 commons-``beanutils 这个库之外(用于做反射)不依赖任何第三方库,因此整体非常轻量级,整个 jar 包大小哪怕发展到现在 5.0 这个大版本,也才 430K

  • 一些比较有特色的特点:

    • 支持运算符重载
    • 原生支持大整数和 BigDecimal 类型及运算,并且通过运算符重载和一般数字类型保持一致的运算方式。
    • 原生支持正则表达式类型及匹配运算符 =~
    • 类 clojure 的 seq 库及 lambda 支持,可以灵活地处理各种集合
  • 开放能力:包括自定义函数接入以及各种定制选项

# 三、Hello World

# 1、Java使用

依赖引入

        <dependency>
            <groupId>com.googlecode.aviator</groupId>
            <artifactId>aviator</artifactId>
            <version>5.3.3</version>
        </dependency>

案例

public class RunScriptExample {
    public static void main(String[] args) throws IOException {
        // Enable java method invocation by reflection.
        AviatorEvaluator.getInstance()
                .setFunctionMissing(JavaMethodReflectionFunctionMissing.getInstance());
        // You can trry to test every script in examples folder by changing the file name.
        Expression exp = AviatorEvaluator.getInstance().compileScript("/Users/10072656/IdeaProjects/spring-demo/src/main/java/com/example/springdemo/examples/hello.av");

        exp.execute();
    }
}

# 2、编译和执行

# 2.1、AviatorScript引擎

AviatorScript编译和执行的入口都是AviatorEvaluator类,该类的一个实例就是一个编译和执行的单元,这个单元我们称为一个 AviatorScript 引擎,AviatorEvaluator.getInstance() 返回一个全局共享的 AviatorScript 引擎。

# 2.2、编译脚本文件

用 compileScript(path) 方法编译一个脚本文件,这个方法对文件路径查找按照下列顺序:

  • path 指定的文件系统绝对或者相对路径
  • user.dir 项目的根目录开始的相对路径
  • classpath 下的绝对和相对路径

找到就尝试读取脚本并动态实时地编译成 JVM 字节码,最终的结果是一个 Expression 对象,每次调用 compileScript(path) 都生成一个新的匿名类和对象,因此如果频繁调用会占满 JVM 的 metaspace,可以通过第二个参数决定是否缓冲:

Expression exp = AviatorEvaluator.getInstance().compileScript("examples/hello.av", true);
exp.execute();

# 2.3、编译文本文件

如果我们脚步存储在其他地方,比如数据库、外部文件等,获取后得到的是一个String对象,我们可以使用comiple方法来编译:

Expression compile = AviatorEvaluator.getInstance().compile("println('Hello, AviatorScript!');");
compile.execute();

# 2.4、执行

编译产生的 Expression 对象,最终都是调用 execute() 方法执行,得到结果。但是 execute 方法还可以接受一个变量列表组成的 map,来注入执行的上下文,我们来一个例子:

public class RunAcExample {
    public static void main(String[] args) {
        String expression = "a + b > 100";
        Expression compile = AviatorEvaluator.compile(expression);
        Object execute = compile.execute(compile.newEnv("a", 80, "b", 70));
        System.out.println(execute);
    }
}

我们定义了一个表达式,但是这个表达式的参数具体数值没有指定,我们可以在执行的时候指定具体的数值。

# 2.5、语法校验

        AviatorEvaluator.validate("1 ++ 2");

# 四、基本类型和语法

# 1、基本类型及运算

# 1.1、整数

整数例如 -99、0、1、2、100……等等,对应的类型是 java 中的 long 类型。AviatorScript 中并没有 byte/short/int 等类型,统一整数类型都为 long,支持的范围也跟 java 语言一样。

let a = 99;
let b = 0xFF;
let c = -99;

println(a + b);
println(a / b);
println(a- b + c);
println(a + b * c);
println(a- (b - c));
println(a/b * b + a % b);
public class Number {
    public static void main(String[] args) throws IOException {
        Expression expression = AviatorEvaluator.getInstance().compileScript("src/main/java/com/example/springdemo/examples/number_demo/number.av");
        Object execute = expression.execute();
        System.out.println(execute);
    }
}

整数相除的结果仍然是整数,比如例子中的 **a/b** 结果就是 0,遵循 java 的整数运算规则。

# 1.2、大整数

let a = 10223372036854774807;  ## Literal BigInteger
let b = 1000N;  ## BigInteger
let c = 1000; ## long type

println(a);

println(a + a);

println(a * a);

println(a + b + c);

# 1.3、浮点数

数字除了整数之外,AviatorScript 同样支持浮点数,但是仅支持 double 类型,也就是双精度 64 位,符合 IEEE754 规范的浮点数。传入的 java float 也将转换为 double 类型。所有的浮点数都被认为是 double 类型。浮点数的表示形式有两种:

  • 十进制的带小数点的数字,比如 1.34159265 , 0.33333 等等。

  • 科学计数法表示,如 1e-2 , 2E3 等等,大小写字母 e 皆可。

let a = 2;
let err = 1e-15;
let root = a;

while math.abs(a - root * root) > err {
  root = (a/root + root) / 2.0;
}

println("square root of 2 is: " + root);

# 1.4、高精度计算

浮点数是无法用于需要精确运算的场景,比如货币运算或者物理公式运算等,这种情况下如果在 Java 里一般推荐使用 BigDecimal 类型,调用它的 add/sub 等方法来做算术运算。

AviatorScript 将 BigDecimal 作为基本类型来支持(下文简称 decimal 类型),只要浮点数以 M 结尾就会识别类型为 deicmal,例如 1.34M 、 0.333M 或者科学计数法 2e-3M 等等。

let a = 2M;
let err = 1e-15M;
let root = a;

while math.abs(a - root * root) > err {
  root = (a/root + root) / 2.0M;
}

println("square root of 2M is: " + root);

# 1.5、数字类型转换

数字类型在运算的时候,会遵循一定的类型转换规则:

  • 单一类型参与的运算,结果仍然为该类型,比如整数和整数相除仍然是整数,double 和 double 运算结果还是 double。
  • 多种类型参与的运算,按照下列顺序: long -> bigint -> decimal -> double 自动提升,比如 long 和 bigint 运算结果为 bigint, long 和 decimal 运算结果为 decimal,任何类型和 double 一起运算结果为 double
let a = 1;
let b = 2;

println("a/b is " + a/b);
println("a/double(b) is " + a/double(b));
a/b is 0
a/double(b) is 0.5

# 1.6、字符串

基本使用

let a = "hello world";

println(a);
println(string.length(a));

// hello world
// 11
let a = "hello world";
let b = 'AviatorScript';

println(a);
println(string.length(a));
println(a + ',' + b + 5); // hello world,AviatorScript5

转义

println('Dennis\'s car');
println('AviatorScript is great.\r\nLet\'s try it!');

// Dennis's car
// AviatorScript is great.
// Let's try it!

字符串赋值

let name = "aviator";
let s = "hello," + name; // hello,aviator 
let name = "aviator";
let a = 1;
let b = 2;
let s = "hello, #{name}, #{a} + #{b} = #{a + b}"; // hello, aviator, 1 + 2 = 3
p(s);

# 1.7、布尔类型

println("3 > 1 is " + (3 > 1));
println("3 >= 1 is " + (3 >= 1));
println("3 >= 3 is " + (3 >= 3));
println("3 < 1 is " + (3 < 1));
println("3 <= 1 is " + (3 <= 1));
println("3 <= 3 is " + (3 <= 3));
println("3 == 1 is " + (3 == 1));
println("3 != 1 is " + (3 != 1));


// 3 > 1 is true
// 3 >= 1 is true
// 3 >= 3 is true
// 3 < 1 is false
// 3 <= 1 is false
// 3 <= 3 is true
// 3 == 1 is false
// 3 != 1 is true

# 1.8、逻辑运算

布尔值可参于逻辑与、逻辑或、逻辑否等运算,假设 x 和 y 的返回结果是布尔值:

  • x && y 表示并且的关系,x 为真,并且 y 为真的情况下,结果为 true,否则 false。

  • x || y 表示或者的关系, x 为真,或者 y 为真,结果就为 true,两者都为假值的时候结果为 false。

  • !x 否定运算符,如果 x 为 true,则结果为 false,反之则为 true。

&& 和 || 都支持短路规则:

  • 如果 x 为假值, x && y 直接返回 false, y 就不进行求值。

  • 如果 x 为真值, x || y 直接返回 true, y 也不进行求值。

# 1.9、三元运算符

let a = 3;
let b = 1;

let c = a > b ? println("a > b") : println("a <= b");

println(c);

// a > b
// null

# 1.10、正则表达式

let p = /^(.*)\.av$/;

println(p == p); ## print true

println("regexp.av" =~ p); ##print true

# 2、运算符

# 2.1、幂运算

引入幂运算符 ** ,原来使用 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

# 2.2、位运算

● &  位与运算
● |  或运算
● ^  异或运算
● << 左移运算
● >> 右移运算
● >>> 无符号右移

# 3、注释

## 这是一行注释
a = 1;
a = 1;  ## 行尾注释

AviatorScript 仅支持 ## 单行注释,如果你需要多行,可以连续使用

# 4、变量

# 4.1、定义和赋值

AviatorScript 中变量的定义和赋值是不可分割的,定义一个变量的同时需要给他赋值

a = 1;
println(type(a));

s = "Hello AviatorScript";
println(type(s));

# 4.2、动态类型

AviatorScript 是动态类型语言,变量的类型随着赋值而改变

s = "Hello AviatorScript";
println(type(s));

s = 99;
println(type(s));

s 原来是一个字符串,我们通过赋值 s = 99 ,他的类型变为了数字,就可以参与算术运算。

# 4.3、nil

当我们想表示一个变量还没有赋值的时候,需要用到 nil 这个特殊类型,它和 java 中的 null 作用一样,表示当前变量还没有赋值。nil 最常见的场景就是用于判断变量是否为 null:

a = nil;
b = 99;

if a == nil {
  println("a is " + type(a));
}

a = 3;

if a !=nil {
  println(a + b);
}

# 4.4、传入变量

String expression = "a-(b-c) > 100";
Expression compiledExp = AviatorEvaluator.compile(expression);
// Execute with injected variables.
Boolean result =
      (Boolean) compiledExp.execute(compiledExp.newEnv("a", 100.3, "b", 45, "c", -199.100));
System.out.println(result);

如果脚本中用到的变量没有传入,并且没有定义,那么默认值将是 nil :

  String expression = "name != nil ? ('hello, ' + name):'who are u?'";
  Expression compiledExp = AviatorEvaluator.compile(expression);
  // we don't inject variable name
  String s = (String) compiledExp.execute();
  System.out.println(s);

  // inject name
  s = (String) compiledExp.execute(compiledExp.newEnv("name", "dennis"));
  System.out.println(s);

# 4.5、引用变量

对于深度嵌套并且同时有数组的变量访问,例如 foo.bars[1].name

AviatorEvaluator.execute("'hello,' + #foo.bars[1].name", env)

引用变量要求以 # 符号开始,变量如果包含特殊字符串,需要使用两个 ` 符号来包围,并且变量名中不能包含其他变量。

# 4.6、访问Java静态变量

p("Math.PI is: " + Math.PI);
p("AviatorEvaluator.VERSION is: " + AviatorEvaluator.VERSION);
p("AviatorEvaluator.COMPILE is: " + AviatorEvaluator.COMPILE);

//Math.PI is: 3.141592653589793
//AviatorEvaluator.VERSION is: 5.1.5-SNAPSHOT
//AviatorEvaluator.COMPILE is: 0

# 5、作用域

# 5.1、let语句

let 语句就是让你在特定作用域内定义一个变量,如果父作用域有同名的变量,将“掩盖”父作用域的变量。


let a = 1;  ## 全局作用域内的 a

{
  ## 嵌套作用域 scope1
  a = 2; ## 不适用 let,访问的还是全局作用域的变量 a
  println(a); ##打印 scope1 内的 a
  a = 3; ##给全局作用域的变量 a 赋值
}

println(a);  ## 打印全局作用域的 a
  
// 2
// 3

# 5.2、嵌套作用域

作用域还可以继续深层嵌套,遵循的规则不变:

  • let 定义当前作用域的变量,这些变量同时可以被它的子作用域访问和修改,离开当前作用域后不可触达。

  • let 定义的变量将“掩盖”父作用域的同名变量。

  • 子作用域可以访问和修改父作用域定义的变量,离开子作用域后修改继续生效

let a = 1;
{
  a = 2;
  let a = 3;
  b = 4;
  {
    a = 5;
    b = 6;
    let c = 7;
    println("a in scope2:" + a);
    println("b in scope2:" + b);
    println("c in scope2:" + c);
  }
  println("a in scope1:" + a);
  println("b in scope1:" + b);
  println("c in scope1:" + c);
}

println("a in global scope:" + a);
println("b in global scope:" + b);
println("c in global scope:" + c);


// a in scope2:5
// b in scope2:6
// c in scope2:7
// a in scope1:5
// b in scope1:6
// c in scope1:null
// a in global scope:2
// b in global scope:null
// c in global scope:null

# 6、多行表达式和return

# 6.1、多行表达式

let a = 1;
let b = 2;
c = a + b;

整个脚本的返回结果默认是最后一个表达式的结果。但是这里需要注意的是,加上分号后,整个表达式的结果将固定为 nil,因此如果你执行上面的脚本,并打印结果,一定是 null,而不是 c 的值。

如果你想返回表达式的值,而不是为 nil,最后一个表达式不加分号即可:

let a = 1;
let b = 2;
c = a + b

# 6.2、return

除了不加分号来返回之外,你也可以用 return 语句来指定返回:

let a = 1;
let b = 2;
c = a + b;

return c;

return 也用于提前返回,结合条件语句可以做更复杂的逻辑判断:

if a < b {
  return "a is less than b.";
}

return a - b;

# 7、创建对象

let d = new java.util.Date();

p(type(d));
p(d);

let year = getYear(d);
let month = getMonth(d);

p("Year is: " + year);
p("Month is: " + month);

// java.util.Date
// Thu Apr 23 11:25:52 CST 2020
// Year is: 120
// Month is: 3

# 8、use语句引用Java类

aviatorscript 支持 use 语句,类似 java 里的 import 语句,可以导入 java 类到当前命名空间,减少在 new 或者 try...catch 等语句里写完整包名的累赘方式。

use java.util.*;

let list = new ArrayList(10);

seq.add(list, 1);
seq.add(list, 2);

p("list[0]=#{list[0]}");
p("list[1]=#{list[1]}");

let set = new HashSet();
seq.add(set, "a");
seq.add(set, "a");

p("set type is: " + type(set));
p("set is: #{set}");

# 五、条件语句

if(false) {
   println("in if body");
} else {
   println("in else body");
}

# 六、循环语句

# 1、普通循环

for i in range(0, 10) {
  println(i);
}

我们可以指定增长的步调:

for i in range(0, 10, 2) {
  println(i);
}

# 2、集合遍历

let m = seq.map("a", 1, "b", 2, "c", 3);

for x in m {
  println(x.key + "=" + x.value);
}

let list = seq.list(1, 2, 3, 4, 5, 6, 7, 8, 9);

let sum = 0;
for x in list {
  sum = sum + x;
}

println("sum of list is "+ sum);

// a=1
// b=2
// c=3
// sum of c is 45

# 3、索引和KV遍历

let a = tuple(1, 2, 3, 4, 5, 6, 7, 8, 9);

for i, x in a {
  assert(i + 1 == x);
  p("a[#{i}] = #{x}");
}

# 4、continue/break/return

for i in range(0, 10) {
  if i % 2 == 0 {
    continue;
  }
  println(i);
}
for i in range(0, 10) {
  if i > 5 {
    break;
  }
  println(i);
}

# 5、while

let sum = 1;

while sum < 1000 {
  sum = sum + sum;
}

println(sum);

# 七、Statement语句和值

# 1、条件语句的值

let a = if (true) {
 	1
};

p("a is :" + type(a) +", " + a);

// a is :long, 1
let a = if (false) {
 	1
};

p("a is :" + type(a) +", " + a);

// a is :nil, null
let a = if (false) {
 	1
} else {
    2
};

p("a is :" + type(a) +", " + a);

// a is :long, 2

# 2、循环语句的值

let b = for x in range(0, 10) {
   x
};
p("b is :" + type(b) +", " + b);

循环语句的结果是最后一次迭代过程中返回的值,因此这里是最后一次迭代 x 的值,也就是 9 :

b is :long, 9
let b = for x in range(0, 10) {
   if x  == 2 {
      break;
   }
};
p("b is :" + type(b) +", " + b);

// b is :nil, null
let b = for x in range(0, 10) {
   if x  == 2 {
      return x;
   }
};
p("b is :" + type(b) +", " + b);

// b is :long, 2

# 3、块(Block)的值

let c = {
  let a = 1;
  let b = 2;
  a + b
};

p("c is :" + type(c) +", " + c);

// c is :long, 3
let c = {
  let a = 1;
  let b = 2;
  
  if a > b {
    return a;
  } else {
    return b;
  }
};

p("c is :" + type(c) +", " + c);

// c is :long, 2

# 八、异常处理

try {
	throw "an exception";
 } catch(e) {
	pst(e);
 } finally {
  p("finally");
 }
  1. throw 抛出了一个字符串,在 AviatorScript 中,可以 **throw 任何东西,**非异常的对象都将被转化包装为标准错误 com.googlecode.aviator.exception.StandardError 类的实例。
  2. catch(e) 没有指定异常的类型, AviatorScript 允许不指定异常类型,等价于 catch(Throwable e) 。
  3. pst(e) 用于打印异常堆栈,也就是 e.printStackTrace() 调用。
  4. AviatorScript 中同样支持 finally 语句,这跟 Java 保持一致。

# 九、函数和闭包

# 1、函数定义和调用

fn add(x, y) {
  return x + y;
}

three = add(1, 2);
println(three); // 3
s = add('hello', ' world');
println(s); // hello world

# 2、函数返回值

fn add(x, y) {
  if type(x) != 'long' || type(y) != 'long' {
    throw "unsupported type";
  }
  x + y
}

println(add(1, 2)); // 3
println(add('hello', ' world')); // unsupported type错误

# 3、函数重载

fn join(s1) {
  "#{s1}"
}
fn join(s1, s2) {
  "#{s1}#{s2}"
}

fn join(s1, s2, s3) {
 "#{s1}#{s2}#{s3}"
}

p(join("hello"));
p(join("hello", " world"));
p(join("hello", " world", ", aviator"));

// hello
// hello world
// hello world, aviator
// null

# 4、不定参数

fn join(sep, &args) {
  let s = "";
  let is_first = true;
  for arg in args {
    if is_first {
      s = s + arg;
      is_first = false;
    }else {
      s = s + sep + arg;
    }
  }

  return s;
}

p(join(" ", "a", "b", "c"));
p(join(",", "a", "b", "c", "d"));
p(join(",", "a"));

// a b c
// a,b,c,d
// a

# 5、匿名函数

匿名函数的基本定义形式是:

lambda (参数1,参数2...) -> 参数体表达式 end
let add = lambda (x,y) ->
  x + y 
end;

three = add(1, 2);
println(three); // 3

# 6、闭包

let counter = lambda() ->
  let c = 0;
  lambda() ->
    let result = c;
    c = c + 1;
    return result;
  end
end;

let c1 = counter();
let c2 = counter();

println("test c1...");
for i in range(0, 10) {
  x = c1();
  println(x);
}

println("test c2...");
for i in range(0, 10) {
  x = c2();
  println(x);
}

c 在函数 counter 中定义,理论上说局部变量在 counter 函数返回后就“销毁”了,但是匿名的结果函数却“捕获”(closure over)了局部变量 c,哪怕在 counter 返回后,仍然可以继续访问到变量 c ,这就称之为闭包(closure), c 就是所谓自由变量。

# 十、数组

# 1、创建数组

tuple 函数可以创建一个固定大小的数组,等价 java 的类型为 Object [] :

let t = tuple(1, 2, "hello", 3.14);

println("type of t: " + type(t));

for x in t {
  println(x);
}

println("count of t: "+ count(t));

println("t[0] = " + t[0]);

t[0] = 100;
println("t[0] = " + t[0]);

// type of t: Object[]
// 1
// 2
// hello
// 3.14
// count of t: 4
// t[0] = 1
// t[0] = 100

# 2、创建指定类型数组

let a = seq.array(int, 1, 2, 3, 4);

println("type(a) is : " + type(a));
println("count(a) is: " + count(a));

这样如果插入一个错误类型,就会报错。

# 3、创建空数组

# 3.1、一维数组

let a = seq.array_of(int, 3);
println("type(a) is : " + type(a));
println("count(a) is: " + count(a));

println("before assignment:");
for x in a {
  println(x);
}

for i in range(0, 3) {
  a[i] = i;
}

println("after assignment:");
for x in a {
  println(x);
}


// type(a) is : int[]
// count(a) is: 3
// before assignment:
// 0
// 0
// 0
// after assignment:
// 0
// 1
// 2

# 3.2、多维数组

let a = seq.array_of(long, 3, 2);

assert(3 == count(a));
assert(2 == count(a[0]));

let x = 0;
for i in range(0, 3) {
  for j in range(0, 2) {
     a[i][j] = x;
     x = x + 1;
  }
}

for i in range(0, 3) {
  for j in range(0, 2) {
    p("a[#{i}][#{j}] = #{a[i][j]}");
  }
}

// a[0][0] = 0
// a[0][1] = 1
// a[1][0] = 2
// a[1][1] = 3
// a[2][0] = 4
// a[2][1] = 5

# 4、遍历数组

let a = seq.array(int, 1, 2, 3.3, 4);

for x in a {
  println(x);
}

# 十一、集合

# 1、List

创建一个链表可以通过 seq.list 函数:

let list = seq.list(1, 2, 3);

上面将创建三个整数组成的 ArrayList 对象, seq.list 接受不定参数,如果不传入任何参数,创建的是一个空链表:

let empty_list = seq.list();

链表和数组类似,也可以通过 a[i] = x 的方式来赋值,前提是 i 落在长度内:

let list = seq.list(1, 2, 3);

list[0] = 4;
list[1] = 5;
list[2] = 6;


println(list); 

# 2、Map

创建一个 HashMap 也很容易,使用 seq.map(k1, v1, k2, v2 ...) 的方式:

let m = seq.map("a", 1, "b", 2, "c", 3, 4, 5);

println(m);

对于 map ,你可以用 m.{key} 的方式来访问:

println("m.a = " + m.a);
println("m.b = " + m.b);
println("m.c = " + m.c);

如果要获取 key 的集合,可以用 seq.keys(m) 函数, value 集合是用 seq.vals 函数:

p("key set: " + seq.keys(m));
p("value set: " + seq.vals(m));

# 3、Set

创建不重复的元素组成的集合 Set,可以用 seq.set :

let s = seq.set(1, 2, 2, "hello", 3.3, "hello");
println(s); // [1, 2, hello, 3.3]
println("type(s) is: " + type(s)); // type(s) is: java.util.HashSet

Set 最常见的操作是判断某个元素是否存在,可以用 include 函数:

println(include(s, 1));
println(include(s, "hello"));	
println(include(s, 100));	

# 4、集合操作

# 4.1、添加元素

let list = seq.list();
let set = seq.set();
let map = seq.map();

## add elements
for i in range(0, 3) {
  seq.add(list, i);
  seq.add(set, i);
  seq.add(map, i, i);
}

println("list: " + list);
println("set: " + set);
println("map: " + map);

// list: [0, 1, 2]
// set: [0, 1, 2]
// map: {0=0, 1=1, 2=2}

# 4.2、访问元素

访问集合中的元素可以用 seq.get(coll, key) 函数,它同时支持数组和所有集合类型:

  • 对于数组和链表, key 就是 0~(len - 1) 的索引位置整数,返回的是该位置的值,超过范围内的访问将抛出异常。
  • 对于 map 来说,key 就是键值对的 key,返回的是对应的 value。
  • 对于 set 来说,key 就是集合里的元素,如果存在,返回该 key 本身,不存在返回 nil。
for i in range(0, 3) {
  assert(i == seq.get(list, i));
  assert(i == seq.get(set, i));
  assert(i == seq.get(map, i));
}
println("seq.get(set, 3) is: " + seq.get(set, 3)); ## nil

# 4.3、判断元素是否存在

for i in range(0, 3) {
  assert(include(list, i));
  assert(include(set, i));
}
assert(!include(list, 5));
assert(!include(set, 5));

对于 map 来说,如果是判断 key 是否存在,需要用 seq.contains_key(coll, key) :

for i in range(0, 3) {
  assert(seq.contains_key(map, i));
}
assert(!seq.contains_key(map, 5));

# 4.4、遍历集合

println("list elements:");
for x in list {
  println(x);
}

println("set elements:");
for x in set {
  println(x);
}

println("map elements:");
for x in map {
  println(x.key + "=" + x.value);
}

# 4.5、删除元素

assert(list == seq.remove(list, 2));
assert(list == seq.remove(list, 4));
assert(set == seq.remove(set, 1));
assert(map == seq.remove(map, 0));
println("list: " + list);
println("set: " + set);
println("map: " + map);

# 参考

AviatorScript文档 (opens new window)

#AviatorScript
上次更新: 2024/06/29, 15:13:44
PromQL
Java 17

← PromQL Java 17→

最近更新
01
基础概念
10-31
02
Pytorch
10-30
03
Numpy
10-30
更多文章>
Theme by Vdoing | Copyright © 2021-2025 旭日 | 蜀ICP备2021000788号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式