位元詩人 [書籍回顧] Programming in Lua, 4th edition 評價

Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

前言

Lua 算是一個相對小眾的語言,通常會學 Lua 的程式人都有某種明確的目的,比較不會把 Lua 當成通用型語言來學。常見的使用方式是搭配遊戲引擎來寫電腦遊戲,像是 Corona 或 Defold 等;或是寫遊戲的外掛,像是魔獸世界 (World of Warcraft);或者是把 Lua 內嵌到宿主軟體中。

Lua 在 5.1、5.2、5.3 版之間有一些不相容的變動,在撰寫 Lua 程式或閱讀 Lua 資料時需注意。本書的 Lua 目標版本是 5.3 版,如果要寫舊版本的 Lua 程式,仍然可參考本書,只是要小幅修改一部分程式。

由於本書的作者是 Lua 的爸爸 Roberto Ierusalimschy,本書相當有指標性,可視為 Lua 的聖經。此外,購買本書時同時在贊助 Lua 的永續發展。

本書共 310 頁,分為 33 章,介於輕量級和中量級之間;但本書字偏多,沒辦法很快讀完。本書分為四部,前三部講 Lua,最後一部講 Lua C API,如果用不到 C 的部分,最後一部可以略過不讀。接下來,我們會逐一介紹各個章節。

I. The Basics

本部講解 Lua 基礎語法元件。

1. Getting Started

本書談到如何撰寫 Lua 程式,分為互動模式 (interactive mode) 和批次模式 (batch mode),實務上都會寫好 Lua 命令稿後再執行,互動模式僅是用來練習語法。接著講解識別字 (identifier)、型別 (types)、註解 (comments) 等基本概念。

2. Interlude: The Eight-Queen Puzzle

本章展示如何用 Lua 解經典的八皇后問題,有空可以欣賞一下。

3. Numbers

本章講述 Lua 的數字型別。Lua 5.3 版引入整數,和先前的版本有一些差異,在撰寫程式時需注意。此外,本章說明數字運算相關的運算子、數學函式庫、產生亂數等議題。

4. Strings

本章講述 Lua 的字串型別。原本 Lua 的字串是 byte 序列,沒有針對特定的編碼來儲存;但 Lua 在 5.3 版引入一個處理 UTF8 字串的函式庫。此外,也講到字串相關的運算子及字串函式庫。

5. Tables

表 (tables) 是 Lua 唯一的資料結構,由於表在 Lua 中相當實用,可做為陣列 (array)、關連式陣列 (associative array)、物件 (object) 等,學習表的使用相當重要。本章學習表的基本用法,不會觸及物件導向程式的部分。

6. Functions

本章講解基本的函式寫法,其他較進階的寫法就留在後續章節中。

7. The External World

本章講解 Lua 的基本輸出入,像是檔案的讀取或寫入、呼叫外部命令、讀取環境變數等。

8. Filling Some Gaps

本章講解一些未歸類的語法特性:

  • 局部變數 (local variables)
  • 區塊 (blocks)
  • 控制結構 (control structures)

因這些內容篇幅偏短,故集中到同一章節來介紹。

II. Real Programming

本部講解一些相對進階的 Lua 語法。

9. Closures

本章帶入一些基本的函數式程式的概念,像是函式物件 (function object) 等。Lua 其實也支援一些函數式程式的特性,本章算是暖身,為之後講解函數式程式做準備。

10. Pattern Matching

正規表示式 (regular expression) 引擎所占的程式碼量較大,若要在 Lua 這類輕薄短小的語言中塞入整個正規表示式引擎,整個語言的空間量會過大,不符內嵌語言的設計目標。因此,Lua 引入 pattern matching 做為替代的方案,本章講解 pattern matching 的語法和使用方式。

11. Interlude: Most Frequent Words

承續上一章,本章展示如何用 Lua 計算文字出現頻率,有空可以欣賞一下。

12. Date and Time

本章講述 Lua 如何處理日期 (date) 和時間 (time) 這兩個在程式中重要的概念,主要是透過 os.dateos.time 這兩個函式庫來處理。

13. Bits and Bytes

本章講述二進位運算及二進位檔案的處理。

14. Data Structures

由於 Lua 只有表 (table) 這個資料結構,本章講述如何用表模擬其他的資料結構,包括陣列 (array)、矩陣 (matrix)、串列 (linked list)、佇列 (queue)、集合 (set)、圖 (graph) 等。本章內容算蠻實用的,有需要的讀者可以閱讀一下。

15. Data Files and Serialization

本章探討資料序列化的議題。一般來說,XML 或 JSON 是常見的資料序列化格式;但 Lua 本身其實也可以做為一種資料描述語言,雖然通用性不若 JSON 來得好,但在 Lua 程式中更加方便。本章展示數個資料序列化的手法;由於資料序列化沒有制式的方法,會隨需求而變,需耐心閱讀本章,從中找出適合自己的方案。

16. Compilation, Execution, and Errors

本章講解幾個和 Lua 運作相關的概念:

  • 動態載入
  • 預先編譯的位元碼 (bytecode)
  • 錯誤處理

雖然不會這些內容還是可以寫 Lua 程式,了解一下對撰寫 Lua 程式會有一些概念。

17. Modules and Packages

當程式變大後,把全部程式寫在同一個命令稿會不易管理;此外,把程式以模組拆開也利於重覆使用。本文介紹 Lua 模組的使用和撰寫,算是重要的章節,可以花時間閱讀。

III. Lua-ism

本部仍在講解 Lua 語法,但屬於較進階的部分。筆者個人以為,除了物件導向程式比較重要外,其他的部分就儘量學習即可,如果不習慣這些特性,不使用仍可撰寫 Lua 程式。

18. Iterators and the Generic for

本章講述撰寫迭代器 (iterators) 的方法以及如何用 for 來走訪迭代器。本章較偏函數式程式設計,如果不習慣這種程式的寫法,可以用其他寫法來代替。

19. Interlude: Markov Chain Algorithom

本章展示如何以 Lua 實作馬可夫鏈,這個演算法相對較難,如果用不到的話,欣賞一下即可。

20. Metatables and Metamethods

Metatable 是 Lua 中用來實作物件導向程式的機制,而 metamethods 則是 Lua 中實作運算子重載的機制,兩者都算是重要的概念。原作者特別把這些內容獨立在一章中,為物件導向程式進行暖身。

21. Object-oriented Programming

沿續上一章的內容,本章講述物件導向程式的寫法。Lua 的物件算是輕量級的,沒有實作所有的物件導向特性,在寫物件時需注意。這兩章應該是這一部中最重要的章節,需仔細閱讀。

22. The Environment

本章說明 Lua 處理全域變數的機制。重點在於利用 _ENV 變數減少命令空間的汙染;另外,應儘量減少全域變數的使用。對於中大型程式來說,全域變數會變成重要的議題。

23. Garbage

本章講述如何在 Lua 中控制垃圾回收相關的議題。一開始寫程式時不會立即用到這個部分,但程式碰到瓶頸時,可以回頭看一看這個部分,看能不能對程式做出一些改善措施。

24. Coroutines

Coroutine 類似於線程 (thread),不過 coroutine 只能單線程運作,這是和線程最大的差異。在 Lua 中 coroutine 有數個用途,像是寫迭代器、寫事件導向程式、寫協同性多工程式等。Coroutine 算是比較進階的概念,一開始無法立即掌握也無妨。

25. Reflection

透過 Lua 的 reflection,我們可以把程式當成資料處理,例如,利用 debug.getinfo 函式來得到函式的元數據 (metadata)。Reflection 多用於除錯 (debugging) 和效能分析 (profiling),我們平常不會用到 reflection 相關的功能。此外,reflection 相關功能可能會拖累程式效能。如果一開始覺得陌生也無妨,因為不會很常用到。

26. Interlude: Multithreading with Coroutines

本章展示如何用 coroutine 寫多線程程式,本章的特點在於利用網路下載的等待時間執行下一段程式,藉以達成有限度的多線程程式。這個範例算比較進階的用法,一開始無法掌握也無妨。

IV. The C API

本部講解如何在 C 程式中嵌入 Lua,如果沒有要在宿主軟體中嵌入 Lua 的話,這部可以略過不看。

由於 Lua 在不同版本間的 C API 有一些不相容,一開始時就要選擇好 Lua 的版本。有些程式人會偏好 LuaJIT 這個非官方的 Lua 實作品,因 LuaJIT 比起 Lua 有更好的效能 (參考這裡),LuaJIT 約略介於 Lua 5.1 和 5.2 版之間。本書的 Lua 目標版本是 5.3,如果要使用別的版本,仍然可以透過本部來學 Lua C API,但要查閱一下其他版本的 API 手冊。

27. An Overview of the C API

本章講述 Lua C API 的基本寫法,重點在於操作 Lua 狀態機。Lua 狀態機以堆疊為基礎,Lua 程式的數據都儲存在這個狀態機中,不會給宿主 C 程式帶來額外的全域變數。本章算是蹲馬步,看完本章還沒辦法直接用這套 API 寫應用程式。

28. Extending Your Application

本章用三個情境來說明如何以 Lua 擴展 C 程式的功能:

  • 讀取常數
  • 讀取表 (tables)
  • 讀取函式 (functions)

透過這些手法,之後我們只要透過修改該 Lua 命令稿就可以更動應用程式的功能,不需重新編譯整個應用程式。

29. Calling C from Lua

在本章中,我們學習如何以 C 撰寫 Lua 函式,透過這些手法,我們可以擴展 Lua 程式的行為。這章剛好和上一章相反,我們在宿主軟體中撰寫函式來擴展 Lua 程式的行為,達到原本 Lua 標準函式庫沒有的行為。

30. Techniques for Writing C Functions

本章沿續前一章,講述一些用於撰寫函式的輔助 API,針對以下情境:

  • 操作陣列
  • 操作字串
  • 儲存函式的狀態

31. User-Defined Types in C

本章學習如何用 C 撰寫 Lua 自定義型別,也就是在 Lua 程式中的 user data。由於自定義型別可以用物件導向的方式來使用,比起函式是更高一階的擴展。

32. Managing Resources

在本章中,我們撰寫可控制外部資源的宿主程式,再將這些程式包裝成 Lua 可用的函式或物件。一些實例像是開啟資料夾或解析 XML 文件等。

33. Threads and States

本章探討如何在 Lua C API 層級撰寫多線程程式。這裡有兩種意義,一種是 coroutine,一種是系統級的多線程程式;前者以 Lua C API 即可完成,後者則需依賴系統上的多線程函式庫。本章提供一個以 POSIX Threads 實作的多線程程式。

結語

雖然 300 多頁乍看不是很多,本書的文字相當紮實,細細閱讀得花上一些時間。本書注重原理講解,大部分程式碼範例偏短且不是完整的程式,而是程式碼片段。歐美的程式設計書籍多用這種風格來寫,好處是易抓到重點,但要自己去花時間寫範例程式,以確認自己所學和書上的知識相符。

關於作者

身為資訊領域碩士,位元詩人 (ByteBard) 認為開發應用程式的目的是為社會帶來價值。如果在這個過程中該軟體能成為永續經營的項目,那就是開發者和使用者雙贏的局面。

位元詩人喜歡用開源技術來解決各式各樣的問題,但必要時對專有技術也不排斥。閒暇之餘,位元詩人將所學寫成文章,放在這個網站上和大家分享。