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 表达式,每个表达式(通常)后面跟着一个分号。
上面的 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 函数只检查第一个参数是否在当前的局部作用域中被定义,因此,如果在不同的作用域级别再次包含,那么对多次包含的检查将不起作用。
include 和 includeOnce 函数是唯一被视为定义的函数,因此它们可以出现在 Sway 模块的定义区域。但是,在表达式中调用这两个函数是合法的,例如
x = includeOnce(:module1.s,"module1.s");
当然,此类对 include 和 includeOnce 的调用不属于定义区域。在以下示例中,只有模块 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 被包含时会被忽略。