Windows 求生手冊:應用程式語言

對於日常生活的任務,已經有許多實用的命令列工具和腳本語言,我們本著程式設計師懶惰的美德,能用現成的工具就不要自己寫。那麼,什麼時候會想要撰寫新的程式呢?其實還是蠻多場合會用到的,本節逐一敘述。

對外發佈新的工具時,如果使用腳本語言,對方需要重新建立相仿的環境,有時候建置環境的過程不一定那麼順利。在類 Unix 系統上比較不會有這個問題,因為在這些系統上建置這樣的環境相對簡單,類 Unix 系統的使用者也很習慣使用各種腳本語言。但在 Windows 中,這些腳本語言都要另外安裝。若直接發布執行檔,可以直接使用,比較節省時間。有些進階使用者會擔心執行檔被加料,筆者通常是原始碼和執行檔同時發布,讓使用者自行選擇。

另外一個考量是程式的效能,在相同演算法的前提下,腳本語言所實作的程式大概都會比較慢,這是腳本語言天生的限制。對於一些不注重效能的任務,也可以用一些將 Python 命令稿轉為 Windows 執行檔的一些方案。這類方案的用意不是要取代編譯語言,實際上也無法取代編譯語言,而是要節省程式設計者撰寫程式的時間。對於小型命令稿,可以考慮使用。

如果有保護原始碼的考量,就會使用編譯語言撰寫程式。其實,這也不是百分之百的防護,真的有心還是可以透過逆向工程觀看程式內部的運作方式。其實,筆者曾經看過某本電腦書籍,提到最有效防止逆向工程的方式就是花錢請個好律師,然後在使用者條款內禁止使用者進行逆向工程。不過,這是高手的世界,已經超出本書預設的讀者群了,我們就不繼續討論這個部分。

傳統上的編譯語言是 C/C++,不過,如果不是要做延伸模組或函式庫,而是要開發應用程式,其實還有一些比較簡易的替代選擇:

  • Java
  • C#
  • Go
  • Rust

本文會逐一介紹這些語言。

Java 不是真正的編譯語言,需要 Java 平台才能運行。經過多年的實務經驗和調整,Java 平台的速度較先前來得更好,現在也有許多建置在 Java 平台上的新興語言,像是 Groovy、Scala、Clojure、Kotlin 等。雖然 Java 平台不是系統預設的一部分,由於 Java 平台相當普遍,很多電腦上都會安裝。用 Java 也可以做命令列程式,但呼叫起來稍嫌囉嗦,有些程式會再用批次檔或 shell script 再將主程式包裝一次,以簡化呼叫的動作。此外,Java 可以透過 JavaFX 來撰寫視窗應用程式。Java 和 C# 同樣都是透過虛擬機器運行,目前 Java 平台對跨平台的支援比 .NET 平台來得好一些,在 Windows 上,.NET 支援較好,讀者可自行取捨所需的工具。

C# 和 Java 的情況類似,C# 也不是真正的編譯語言,需要 .NET 平台才能運行。雖然 C# 程式會編譯成 EXE 和 DLL 檔,但那不是真正的機械碼,而是一種特殊的中介檔。C# 在 Windows 平台享有 VIP 級的待運,Windows 即內建 .NET 平台,但 C# 並不是實質的跨平台語言,Mono 並不是一個普及的平台;微軟所開發的跨平台開發環境 .NET Core 已經正式進入 2.0 版了,目前能用的項目為終端機程式、函式庫和 ASP.NET;雖然 .NET Core 可以將 C# 程式碼轉為機械碼,經筆者實測,這項功能還不完整,有時會轉換失敗。如果程式只在 Windows 平台上發布,用 C# 當然可行,但如果有同時要在其他平台發布程式,則要再評估是否合適。

Go 是 Google 所創造的新興編譯語言,有點像是 C 的進化版,略為加強物件導向方面的語法,簡化一些瑣碎的記憶體管理等,再加上一些易學的語法特性。Go 已經用在許多實際的專案了,像是 Docker 就是用 Go 實作的。對於命令列工具來說,用 Go 寫非常方便,實際上也有用 Go 做為命令列工具的案例,像是 c6,一個用 Go 實作的 SASS 編譯器。如果要用來撰寫網頁程式及網路服務,更是 Go 的強項,畢竟這是 Go 原來所要完成的目標。但對於其他項目,用 Go 寫不一定比較吃香。到目前為止,Go 沒有官方的圖形函式庫,只能靠社群各自努力;最近 Go 語言在圖形介面函式庫上有改善的跡象,但長期發展如何,仍需觀察。要注意的是,雖然 Go 可以輸出 C 函式庫,但不能輸出結構 (struct),使得這項功能的實用度大打折扣。

Rust 是 Mozilla 所贊助的新興編譯語言,設計的目標是撰寫安全且高效能的應用程式。Rust 吸收許多函數式程式語言的特色,但比純函數式語言來得簡單;Rust 有豐富的語法功能,但不易上手,尤其是所有權 (ownership) 的部分,需花一段時間適應。不論是要撰寫應用程式或是輸出 C 函式庫,使用 Rust 都是相當方便的選擇;然而,Rust 的標準函式庫功能較少,需要找尋合適的第三方方案或是自行實作。和 Go 相似,目前 Rust 對圖形函式庫的支援較為單薄。

使用 Go 或 Rust 撰寫應用程式,會比使用 C/C++ 來得簡單。主要的原因在於這些語言本身及其標準函式庫是跨平台的,同一份程式碼不需改動即可在不同平台上編譯。另外,這些語言內建編譯軟體時所需的 toolchain,不需額外呼叫其他的軟體來編譯軟體。在語言機制上,這些語言也比 C/C++ 來得簡單,像是對字串的操作較接近高階語言,不需處理記憶體相關的細節等。然而,這些新興語言較老牌的 C++ 或 Java 等語言來說,社群資源不夠豐富,有時仍要回頭呼叫第三方 C/C++ 函式庫,可能會使專案相依性變得複雜。