学习总结录 学习总结录
首页
归档
分类
标签
  • 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
目录

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-2024 旭日 | 蜀ICP备2021000788号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式