OK,這是在這篇『學習新程式語言的十五項修練』中找到的,我找不到原文最原始的網頁,所以附上 digg 的連結,裡頭也有一些討論。
接著會試著用 D 語言來完成這幾個練習題,用的編譯器版本是 GDC v0.24,而標準函式庫則是採用 Tango v0.99.7,作業系統為 Linux 或 Windows,如果有特別的作業系統或第三方函式庫需求,我會特別標出來。
題目採用原來英文版本的,因為題目的英文都很簡單,所以直接用英文版的,應該會比較接近題目的原意。
第一個題目是無限迴圈:
Display series of numbers (1,2,3,4, 5....etc) in an infinite loop. The program should quit if someone hits a specific key (Say ESCAPE key).
看起來雖然像是非常簡單的題目,但事實上並非如此,因為很不幸的,C 語言與 D 語言還有 Tango 的標準輸入輸出函式庫,全都是 line-buffered,到目前為止,我還找不到可以直接用標準函式庫硬幹出來,而且在 Linux 與 Windows 上都可以跑的方法。
我已經在 Stack Overflow 這個網站上提問,不過目前看來情況不怎麼樂觀。
另外,這個題目看起來簡單,但我覺得其實暗藏玄機啊!你要怎麼樣在印迴圈的同時監控使用者有沒有按下 ESC 鍵呢?而且如果使用者沒按 ESC 鍵,就應該要一直在螢幕上顯示數字,不能有停下來等使用者輸入的情況。
到最後,我的解決方式如下--用一個 Thread 來當 Keyboard Handler,專門監測使用者的按鍵動作。當然,因為標準函式庫都是 line-buffered,我只好借助 ncurses 這個 Linux 下常見的函式庫,利用裡面的函式來截取使用者按鍵的動作。
當然,ncurses 是 C 的函式庫,不過既然 D 可以直接與 C 語言進行接合(interface with C),所以這不是問題,只是這麼一來這隻程式就變成只能在 Linux 上跑囉。
以下就是這次的第一項修練,其實程式滿短的,應該很容易理解是在做什麼。而在這個範例中,你可以學到:
- 如何使用 C 語言的第三方函式庫。
- 如何建立 Thread。
=============================================
import tango.io.Stdout;
import tango.core.Thread;
/******************************************
* 宣告用到的 ncurses 函式原型,只要像這
* 樣宣告後,就可以直接在程式碼中用 C 函
* 式庫中的函式。
*
* 編譯時,如果用的是 dsss,就用
* dsss -llncurses 連結 ncurses 函式庫。
*****************************************/
extern(C)
{
void * initscr();
int cbreak ();
int getch();
int endwin();
int noecho();
}
/******************************************
* 這個函式會用來建立一個 Thread 監視使用
* 者的鍵盤輸入。
*****************************************/
void keyboardHandler ()
{
initscr(); // 初始化 ncurses
cbreak(); // 讓標準輸不要做 buffer
noecho(); // 不顯示使用者按下的鍵
// 一直重復等使用者的按鍵輸入,直到使
// 用者按下 ESC。
while (getch() != 27) {
}
endwin(); // 結束 ncurses
}
/******************************************
* 主程式,不用講了。
*****************************************/
void main ()
{
// 建立並執行監視鍵盤的 Thread
Thread handler = new Thread (
&keyboardHandler
);
handler.start();
// 無限迴圈
for (int i = 0; ; i++) {
Stdout.format ("{}\r\n", i).flush;
// 如果建立的 Thread 已經不再執行狀
// 態,代表使用者按下了 ESC 鍵,跳
// 出無限迴圈。
if (handler.isRunning == false) {
break;
}
}
return 0;
}
回響