跳转到内容

Sway 参考手册/将代码存储在文件中

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

一段时间后,反复剪切粘贴到 Sway 解释器中会变得相当繁琐。更有效的方法是将你的程序存储在一个文本文件中,然后加载该文件。

我使用 vim 作为我的文本编辑器。Vim 是一个由程序员为程序员编写的编辑器(emacs 是另一个这样的编辑器),严肃的计算机科学家和程序员应该学习 vim(或 emacs)。

你的第一个程序

[编辑 | 编辑源代码]

创建一个名为 hello.s 的文本文件。名称实际上并不重要,也不必以 .s 结尾(.s 是一个约定,提醒我们这个文件包含 Sway 源代码)。将以下内容放入文件中

   println("hello, world!");

保存你的工作并退出文本编辑器。现在在系统提示符下(不是 Sway 解释器提示符!)执行以下命令

   sway hello.s

你应该在你的控制台上看到以下短语

   hello, world!

显示。

   lusth@warka:~$ sway hello.s
   hello, world!
   lusth@warka:~$

这是一个使用 Linux 的跟踪lusth@warka:~$是我的系统提示符。

一个整洁的宏

[编辑 | 编辑源代码]

你可以做的更有用的事情之一是设置一个 vim 宏。编辑(或创建)你主目录下的 .exrc 文件,并添加以下行

   set ai sm sw=4
   map @ :!sway %^V^M

第一行设置了一些有用的参数:自动缩进和显示匹配。在sw=4将缩进设置为四个空格。下一行使“@”键在按下时在当前正在编辑的文件上运行 Sway 解释器(在按“@”键之前先保存你的工作)。宏中的 ^V^M 部分不是四个字符 ^ V ^ M,而是两个字符 <Ctrl>-v 和 <Ctrl>-m。只是当你键入 <Ctrl>-v<Ctrl>-m 时,它会显示为 ^V^M。

编写 Sway 程序

[编辑 | 编辑源代码]

典型的 Sway 程序由两个部分组成。第一部分由变量和函数定义组成。下一部分由语句组成,这些语句是 Sway 表达式,每个表达式(通常)后面跟着一个分号。

上面的 hello.s' 文件是一个没有 定义并且只有一个语句的程序。仅由定义组成的 Sway 程序通常在没有输出到屏幕的情况下运行。此类程序通常是为了被包含到其他程序中而专门编写的。

通常,其中一个函数定义是一个名为 main 的函数(按照惯例);这个函数不接受任何参数。程序的最后一行是对 main 的调用。以下是使用该约定的 hello.s 的重写。

   function main()
       {
       println("hello, world!");
       }
   main();

这个版本的输出与前一个版本完全相同。

定义顺序

[编辑 | 编辑源代码]

函数或变量必须在使用之前定义。这个程序会产生错误

   var x = y * y;
   var y = 3;

因为在定义 y 之前,x 无法赋值。然而,这个程序是合法的

   function x()
       {
       y() * y();
       }
   function y()
       {
       3;
       }
   x();

因为即使函数 x 的主体引用了函数 y,函数 y 也在函数 x 被调用(程序的最后一条语句)时被定义了。

包含代码

[编辑 | 编辑源代码]

可以使用 include 函数将一个 Sway 模块包含到另一个模块中

   include("moduleX.s");

其中 moduleX.s 是你想要包含其 Sway 定义的文件的名称。包含一个模块会导入该模块中的所有顶级定义。包含模块中的定义之外的语句会被忽略,不会被执行。

如果 moduleX.s 包含其他模块,那么那些模块也会被包含。

防止多次包含

[编辑 | 编辑源代码]

有时,在复杂的实现中,一个模块可能会被包含多次。通常,这会导致对同一项的多次定义,虽然会造成浪费,但通常不会造成任何损害。但是,请考虑一个模块包含另一个模块,反之亦然的情况。以下是一个示例。一个模块 fact.s 有以下实现

   include("fib.s");
   function fact(n)
       {
       if (n < 2,1,n * fact(n - 1));
       }
   println("fib(5) is ",fib(5));
   println("fact(5) is ",fact(5));

另一个模块 fib.s 有以下代码

   include("fact.s");
   function fib(n)
       {
       if (n < 2,v,fib(n - 2) * fib(n - 1));
       }
   println("fib(6) is ",fib(6));
   println("fact(6) is ",fact(6));

尝试在任何一个模块上运行 Sway 都会导致内存不足错误,因为每个文件都会被反复包含(fib.s 包含 fact.s,而 fact.s 包含 fib.s,等等)。可以使用 includeOnce 函数来防止多次包含。以下是对每个模块的重写。

   includeOnce(fib.s,"fib.s");
   function fact(n)
       {
       if (n < 2,1,n * fact(n - 1));
       }
   println("fib(5) is ",fib(5));
   println("fact(5) is ",fact(5));
   includeOnce(fact.s,"fact.s");
   function fib(n)
       {
       if (n < 2,v,fib(n - 2) * fib(n - 1));
       }
   println("fib(6) is ",fib(6));
   println("fact(6) is ",fact(6));

运行 fact.s 程序将产生

   fib(5) is 5
   fact(5) is 120

而运行 fib.s 程序将产生

   fib(6) is 8
   fact(6) is 720

传递给 includeOnce 函数的第一个参数必须是一个变量,但这个变量不必被定义。includeOnce 函数会检查它的第一个参数是否已被定义。如果变量已经存在,则不会采取任何进一步的措施。如果没有,includeOnce 会用一个值为:true的值来定义它,然后包含第二个参数指定的模块。由于 Sway 对变量名的命名规则比较宽松,大多数没有空格的文件名(包括 Unix 风格的路径)都是合法的变量名。按照惯例,传递给 includeOnce 的变量名是包含该模块的文件的名称;虽然任何变量名都可以。但是,如果存在名称冲突,并且变量已经通过其他方式声明,那么给定的模块将不会被包含。includeOnce 函数只检查第一个参数是否在当前的局部作用域中被定义,因此,如果在不同的作用域级别再次包含,那么对多次包含的检查将不起作用。

includeincludeOnce 函数是唯一被视为定义的函数,因此它们可以出现在 Sway 模块的定义区域。但是,在表达式中调用这两个函数是合法的,例如

   x = includeOnce(:module1.s,"module1.s");

当然,此类对 includeincludeOnce 的调用不属于定义区域。在以下示例中,只有模块 B 和 C 中的顶级定义包含在 A 中。

   include("B.s");
   ...
   include("C.s");
   var x;
   x = include("D.s");

来自模块 D.s 的定义没有被包含到 A.s 中,因为只有 B.s 的定义区域被包含到 A.s 中(这会导致 C.s 被包含)。对包含 D.s 的调用在表达式区域,在 B.s 被包含时会被忽略。


函数 · 关于函数的更多信息

华夏公益教科书