循环语句通常用于遍历一个集合,或者重复执行若干指令,直到满足某个条件等等。 AviatorScript 支持 forwhile 两种循环语句,分别介绍如下。

for 语句:遍历集合

for ... in 语句通常用于遍历一个集合,例如下面是遍历 0 到 9 的数字,并打印:

  1. ## examples/for_range1.av
  2. for i in range(0, 10) {
  3. println(i);
  4. }

打印出:

  1. 0
  2. 1
  3. 2
  4. 3
  5. 4
  6. 5
  7. 6
  8. 7
  9. 8
  10. 9

其中 range(start, end) 函数用于创建一个 [start, end) 区间的整数集合,在迭代过程中,将 i 绑定到集合中的每个元素上,然后执行 {...} 里的代码块。大括号也是必需的,不能因为代码块是单行语句而忽略,这跟 java 是不同的。

range 函数还可以接受第三个参数,表示递增的 step 大小(不传默认 step 就是 1),比如我们可以打印 0 到 9 之间的偶数:

  1. ## examples/for_range2.av
  2. for i in range(0, 10, 2) {
  3. println(i);
  4. }

打印:

  1. 0
  2. 2
  3. 4
  4. 6
  5. 8

for .. in 可以用于任何集合结构,比如数组、 java.util.Listjava.util.Map 等等:

  1. ## examples/for_seq.av
  2. let m = seq.map("a", 1, "b", 2, "c", 3);
  3. for x in m {
  4. println(x.key + "=" + x.value);
  5. }
  6. let list = seq.list(1, 2, 3, 4, 5, 6, 7, 8, 9);
  7. let sum = 0;
  8. for x in list {
  9. sum = sum + x;
  10. }
  11. println("sum of list is "+ sum);

这里 m 是一个 HashMap ,通过 seq.map 函数创建,里面是三个键值对 a=1, b=2, c=3 ,我们也可以通过 for...in 语句来遍历,并且通过 x.keyx.value 来访问每一对的键值。

list 就是一个 1 到 9 整数组成的 List ,我们利用 for 语句迭代累计它们的和 sum 并打印。

最终输出:

  1. a=1
  2. b=2
  3. c=3
  4. sum of c is 45

关于 for 和集合 Sequence 的关系可以继续阅读第八章

索引和 KV 遍历

从 5.2.4 版本开始, for 语句还支持迭代遍历过程带上索引或者 key/value:

  1. ## examples/for_index_kv.av
  2. let a = tuple(1, 2, 3, 4, 5, 6, 7, 8, 9);
  3. for i, x in a {
  4. assert(i + 1 == x);
  5. p("a[#{i}] = #{x}");
  6. }
  7. let m = seq.map("a", 1, "b", 2, "c", 3);
  8. for k, v in m {
  9. p("#{k} = #{v}");
  10. if k == "a" {
  11. assert(v == 1);
  12. }elsif k == 'b' {
  13. assert(v == 2);
  14. }elsif k == 'c' {
  15. assert(v == 3);
  16. }else {
  17. throw "should not happen";
  18. }
  19. }

通过 key[index], value 的形式就可以带上索引或者 KV 对(仅限 Map 类型)来遍历,输出:

  1. a[0] = 1
  2. a[1] = 2
  3. a[2] = 3
  4. a[3] = 4
  5. a[4] = 5
  6. a[5] = 6
  7. a[6] = 7
  8. a[7] = 8
  9. a[8] = 9
  10. a = 1
  11. b = 2
  12. c = 3
  13. null

continue/break/return

如果你想在执行代码块中途跳过剩余代码,继续下个迭代,可以用 continue ,比如下面的示例,跳过所有偶数,也就是打印奇数:

  1. ## examples/for_continue.av
  2. for i in range(0, 10) {
  3. if i % 2 == 0 {
  4. continue;
  5. }
  6. println(i);
  7. }

同样,如果想中途跳出迭代,你可以用 break:

  1. ## examples/for_break.av
  2. for i in range(0, 10) {
  3. if i > 5 {
  4. break;
  5. }
  6. println(i);
  7. }

当 i 大于 5 的时候,我们就跳出循环,因此只打印了:

  1. 0
  2. 1
  3. 2
  4. 3
  5. 4
  6. 5

return 有类似 break 的效果,也可以从循环中跳出,但是它会将整个脚本(或者函数)中断执行并返回,而不仅仅是跳出循环:

  1. ## examples/for_return.av
  2. for i in range(0, 10) {
  3. if i > 5 {
  4. return;
  5. }
  6. println(i);
  7. }
  8. println("Can't reach here");

当 i 大于 5 的时候,我们就直接返回了, for 循环之后的代码也不会执行,因此也不会打印 Can't reach here

while 语句

while 循环本质上是条件语句和循环的结合,当满足一定条件下,不停地执行一段代码块,直到条件变为否定:

  1. ## examples/while1.av
  2. let sum = 1;
  3. while sum < 1000 {
  4. sum = sum + sum;
  5. }
  6. println(sum);

sum 从 1 开始,不停地累加自身,直到超过 1000 才终止,这里输出:

  1. 1024

while 后面跟 if 一样跟着一个布尔表达式,括号同样可以省略,但是代码块必须用大括号包围起来,这跟 if/for 也是一样的。

同样, while 也可以用 break 和 continue 语句,比如上面的例子我们可以改写成:

  1. ## examples/while2.av
  2. let sum = 1;
  3. while true {
  4. sum = sum + sum;
  5. if sum > 1000 {
  6. break;
  7. }
  8. }
  9. println(sum);

使用 while true 来无限循环,直到 sum 大于 1000 就 break 跳出。

return/continue 的使用和 for 类似,不再赘述。

循环语句也可以多层嵌套,这跟其他语言都没有什么两样:

  1. let c = 0;
  2. for i in range(0, 10) {
  3. for j in range(0, 10) {
  4. c = c + i * j;
  5. }
  6. }
  7. println(c);