跳转到内容

Sway 参考手册/循环

来自维基教科书,开放的书,开放的世界

有时,程序员希望多次执行一段代码。这种任务通常使用循环来完成。Sway 中最基本的循环结构是 while 循环,其格式为...

   whileloop: 'while' '(' expr ')' block

其中 expr 是任何解析为符号 :true 或 :false 的 Sway 表达式。

while 循环在执行循环主体之前测试其条件。如果初始测试失败,则主体根本不会执行。例如;

   var i = 10;
   while (i < 10)
       {
       print(i);
       i = i + 1;
       }

不会打印任何内容,因为测试立即失败。在这个例子中,然而

   var i = 0;
   while (i < 10)
       {
       print(i);
       i = i + 1;
       }


循环打印出数字 0 到 9

   0123456789
   

while 循环重复执行其主体(循环的块部分)(只要条件保持为 true)。

要编写一个无限循环,请使用 :true 作为测试表达式

   while (:true)
       {
       var i = getInput();
       process(i);
       }

循环是函数调用

[编辑 | 编辑源代码]

if 一样,所有 Sway 循环都是函数调用,通常带有近似块参数。如果需要,可以将小的近似块作为常规参数移到括号内。此外,if 的分号规则也适用于循环:循环本身具有近似块参数,后面不加分号。如果你要使用循环的返回值(对于 while,如果测试表达式最初为 true,则为 :true,如果测试表达式最初为 false,则为 :false),你需要在整个表达式后加上分号。

其他循环

[编辑 | 编辑源代码]

因为循环在 Sway 中很容易编写,所以只有 while 循环是内置的。其他循环可以在 "basics" 库中找到。要使用 "basics" 库,请添加函数调用

   include("basics");

到源代码文件的最顶端。

do-until 循环类似于 while 循环,但循环的主体在进行测试之前执行一次。例如

   var i = 10;
   do-until (i == 10) //note the test
       {
       print(i);
       i = i + 1;
       }

打印出 i 的值一次

   10

请注意,do-until 在测试成功之前运行,这与 while 相反,while 在测试失败之前运行。

do-until 循环并不经常使用,尽管有时它对于处理交互式输入很有用。你总是可以将 do-until 编写为 while 循环。考虑这个循环

   do-until (r == 0)
       {
       r = n / d;
       n = d;
       d = r;
       }

它可以被重写为一个 while 循环,如下...

   finished = :false;
   while (!finished)
       {
       r = n / d;
       n = d;
       d = r;
       finished = (r == 0);
       }

请注意,变量 finished 被初始化为 :false,以确保循环主体至少进入一次。在循环底部,finished 被设置为 do-until 测试结果。

通常,do-until 更易于阅读和理解。

for 循环

[编辑 | 编辑源代码]

在许多程序中发现的另一个循环是 for 循环。for 循环由四个主要部分组成

  • 初始化步骤
  • 测试
  • 主体
  • 更新

请注意,这些组件与 while 循环完全对应

   i = 0;                        // initialize
   while (i < MAX)               // test
       {                         // body
       inspect(i);
       i = i + 1;                // update (in body)
       } 

其中更新通常是循环主体中的最后一条语句。相应的 for 循环为

   for (i = 0, i < MAX, i = i + 1)  // init, test, update
       {                            // body
       inspect(i);
       }

看看更新是如何从主体中移出的。

for 循环通常用于遍历数组中的每个元素

    for (i = 0, i < length(items), i = i + 1)
        {
        a[i] = b[i] * c[i]; 
        }


for 循环是一个计数循环。对于大多数(但并非全部)计数循环,循环变量(在本例中为 i)被初始化为零,循环测试(在本例中为i < length(items)) 被配置为只要循环变量严格小于计数的最大值就成功。如果循环主体要执行 n 次,则循环看起来像

   for (i = 0, i < n, i = i + 1)
       {
       ...
       }

这种约定源于 Sway 中的数组(在后面的章节中详细介绍)使用 "基于零的索引"。也就是说,数组的第一个元素位于索引零处,第二个元素位于索引一处,依此类推。

除非有充分的理由,否则你应该始终使用这种约定[1]

for-each 循环

[编辑 | 编辑源代码]

for-each 循环对于遍历数组和列表也很有用。它没有明确计数,但是

   for-each (s,items)
       {
       inspect(s);
       }

在这个循环中,items 中的每个元素依次绑定到变量 s。循环主体执行的次数与数组或列表中的元素数量相同。请注意,与等效的 for 循环相比,for-each 循环要短得多

   for (i = 0; i < length(item); i = i + 1)
       {
       var s = items[i];
       inspect(s);
       }

它明确地计数。

退出循环

[编辑 | 编辑源代码]

除了循环条件或测试失败(或在 do-until 的情况下成功)之外,还有许多方法可以退出循环。即使在循环中间,也可以从函数中返回。这种技术经常用于搜索数组

   function find(x,items)
       {
       var s;
       
       for-each(s,items)
           {
           if (x == s)
               {
               return :true;
               }
           }
           
       :false;
       }

请注意,如果未找到该项目,则循环最终会终止,并通过返回 :false 来表示失败。

你也可以通过调用 break 来退出循环,而无需完全退出函数

   i = 0;
   while (i < 10)
       {
       if (i > 5) { break(); }
       inspect(i);
       }
   println(:done);

运行此代码将产生

   i is 0
   i is 1
   i is 2
   i is 3
   i is 4
   i is 5
   done

你需要包含 basics 才能使用 break。你也可以简单地抛出一个类型为 :break 的异常

   i = 0;
   while (i < 10)
       {
       if (i > 5) { throw(:break,0); }
       inspect(i);
       }
   println(:done);

最后,你可以通过使用 exit 函数来退出程序来退出循环

   while (1)
       {
       var input = getInput();
       if (reallyBad(input))
           {
           exit(-1);            //non-zero exit code
           }
       }

按照惯例,退出代码为零的 Sway 程序表示处理正常进行。非零退出代码表示发生某种致命错误。

  1. 相信我吧。


条件语句 · 递归

华夏公益教科书