跳轉到內容

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 被包含時會被忽略。


函式 · 關於函式的更多資訊

華夏公益教科書