位元詩人 [Lua] 程式設計教學:變數 (Variable) 和資料型別 (Data Type)

Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

前言

在本文中,我們介紹幾個 Lua 程式的基本概念,包括變數、資料型別等。

註解 (Comments)

在程式中,註解的部分不會執行,程式設計者可在註解中加入一般文字。

註解的用途在於記錄當下撰寫程式的想法或意圖,以利之後修改程式時可較快回復記憶。Lua 中撰寫註解的方式如下:

  • -- ...:單行註解
  • --[[ ... --]]:多行註解

宣告和使用變數 (Variables)

電腦程式時常需要操作資料 (data) 以達成特定功能,我們可以將變數 (variable) 視為資料的標籤,Lua 程式透過變數可以存取資料。

以下變數 msg 儲存字串 Hello World,再由 print 函式來呼叫:

msg = "Hello World"
print(msg)

函式 (function) 是預先寫好的程式區塊,需要時藉由呼叫 (call) 函式即可使用該函式。print 是 Lua 內建的函式,可將資料轉為字串印出。

Lua 的變數沒有綁定特定的型別 (data type),型別由值本身決定:

var = "Hello World"
assert(type(var) == "string")

var = 12345
assert(type(var) == "number")

在這裡,我們使用兩個內建函式,assert 會斷定函式內的值是否為真,不為真時會中止程式,type 會回傳變數的型別,回傳的值本身為字串。

變數的要素

一般來說,變數包含三個要素:

  • 變數的型別 (data type)
  • 變數的識別字 (identifier)
  • 變數的值 (value)

但 Lua 是動態型別語言,變數不和型別綁定,而是由值本身來決定變數當下的型別。值的型別會在執行 Lua 程式的過程中動態檢查。

全域變數和局部變數

Lua 比較大的問題在於其變數預設是全域變數 (global variable),而全域變數的有效範圍會超過單一的 Lua 命令稿。當程式規模變大時,這項特性很容易造成程式中難以發現的臭蟲 (bug)。比較好的方式是用 local 宣告局部變數 (local variable):

local msg = "Hello World"
print(msg)

使用 local 宣告的變數,其可視度 (scope) 不會超出該 Lua 命令稿,減少程式出現 bug 的機會。最好養成每個變數都用 local 修飾詞宣告的習慣,除非明確知道自己要寫全域變數。

附帶一提,如果在同一個檔案內要隔離變數的可視區域,可用 do ... end 區塊,該區塊可跨越多行:

do
  -- Do something here.
end

在每個 do ... end 區塊內的變數和其他區塊是獨立的,可用來避免命名空間的汙染。

資料型別 (Data Types)

如同大部分的程式語言,Lua 具有資料型別 (data type) 的概念。在電腦程式中,資料型別規範可用的操作,像是數字可以加減乘除、布林可以進行布林運算等。

Lua 包括以下八種資料型別:

  • nil
  • 布林 (boolean)
  • 數字 (number)
  • 字串 (string)
  • 表 (table)
  • 函式 (function)
  • thread
  • userdata

我們將簡要地說明這八種型別。

Nil

Lua 用 nil 表示沒有值,在變數宣告後但未設置其他值時,該變數的的值即為 nil。將變數設為 nil 即可以刪除此變數。

布林 (Boolean)

布林 (boolean) 包括 truefalse,用於邏輯判斷。要注意的是,Lua 的值除了 falsenil 外皆為 true,像是零、空字串、空 table 等皆視為 true,故不能用空值判定為偽 (false),這和 C 語言略有不同。

數字 (Numbers)

在 5.3 版以前,Lua 的數字皆為倍精度浮點數 (double-precision floating-point),沒有整數 (integer);5.3 版後引入整數型別。在進行數字運算時,若有使用小數點的部位,需注意可能的誤差。

例如,在以下程式中,程式會因一些微小的誤差引發錯誤:

-- Error
assert(0.1 + 0.2 - 0.3 == 0.0)

在撰寫 Lua 程式時,要注意當下的 Lua 版本,因為會影響數字的行為。

此外,Lua 的數字可用十進位數或十六進位數表示,例如 0xff

字串 (Strings)

Lua 字串是 byte 陣列,沒有限定特別的編碼,甚至可以存二進元數據。從 5.3 版起,Lua 另外有處理 UTF-8 編碼字串的小型函式庫。

相較於主流語言,Lua 對於字串處理能力相對薄弱,也沒有內建的常規表示式 (regular expression) 函式庫;Lua 不放入常規表示式的原因是要維持整個 Lua 直譯器在適當的大小,一整套的常規表示式引擎對內嵌語言來說太大了。

Lua 是弱型別語言,字串和數字會自動轉換,如下例:

-- Convert numbers to strings.
assert((10 .. 20) == "1020")

-- Convert strings to numbers.
assert(("10" + 1) == 11)

要小心這樣的特性可能會引起難以偵測的臭蟲。

表 (Table)

表 (table) 是 Lua 唯一的資料結構,內部為關連式陣列 (associative array)。表在 Lua 相當重要,除了用來做為資料結構外,也是 Lua 物件導向程式的基礎。我們將於後續文章討論表的使用方式以及物件導向程式。

函式 (Function)

Lua 的函式除了用來包裝程式碼區塊外,也可做為值使用,也就是說,Lua 可以撰寫函數式程式。我們將於後續文章介紹函式和函數式程式。

Thread

雖然 Lua 號稱有執行緒,但 Lua 缺乏真正的多執行緒,而以 coroutine 做為協同式多工的機制。

Userdata

Userdata 主要是用來和宿主程式溝通,Lua 程式本身不處理 userdata。傳統上,宿主程式以 C 或 C++ 來撰寫,不過也可能是其他的程式語言。

關於作者

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

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