1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 |
-- 單行註釋 --[[ [多行註釋] --]] ---------- - 1. 變數 & 控制流 ---------- num = 23 -- 數字都是雙精度 str = 'aspythonstring' -- 像 Python 一樣不可變 str = "aspythonuse" -- 可以雙引號 str = [[ 像 Python 的多行註釋可用於 表示多行字串一樣 方便 ]] bol = nil -- 未定義;支援垃圾回收 -- 縮排只為易讀性,像 Matlab 一樣以 end 結尾 while num < 50 do num = num + 1 -- 沒有 ++ 或 += 自增操作符號 end -- IF 條件開關 if num > 40 then print('> 40') elseif s ~= 'aspython' then -- ~= 表示 != io.write('s is not aspython') -- 風騷的標準輸出 else thisIsGlobal = 5 -- 駝峰式命名 -- 顯示宣告區域性變數(像 Javascript 一樣) local line = io.read() -- .. 作為字串連線符 print('凜冬將至' .. line) end -- 引用未定義變數將返回 nil ,這不是錯誤 foo = anUnknownVariable -- 等價於 foo = nil aBoolValue = false -- 只有 nil 與 false 為邏輯假; 數字 0 與空字串 '' 為真! if not aBoolValue then print('false') end -- 像 Python 一樣運用 'or' 和 'and' -- 得到 C 語言中 a ? b : c 的效果;需注意 b = false 或 nil 的情況 ans = aBoolValue and 'yes' or 'no' karlSum = 0 for i = 1, 100 do -- 像 Matlab 一樣的遞增語法,包括兩端,如同數學中[1, 100] karlSum = karlSum + i end -- Step 為 2 遞減的方式 '100, 1, -2' for j = 100, 1, -2 then print(j) end -- 綜上,範圍可表示為 "begin, end [, step]" -- 另一個迴圈控制 num = 23 repeat print('凡人必有一死') num = num - 1 until num == 0 ---------- - 2. 函式 ---------- function fib(n) if n < 2 then return 1 end return fib(n - 2) + fib(n - 1) end -- Javascript 一樣的匿名函式與閉包 function adder(x) -- 返回一個函式 -- 閉包內封存 x 值 return function (y) return x + y end end a1 = adder(9) a2 = adder(36) print(a1(16)) --> 25 print(a2(64)) --> 100 -- 遇到不匹配的列表長度時 -- 過長的變數將被賦予 nil -- 過長的值將被忽略 x, y, z = 1, 2, 3, 4 -- 4 將被忽略 function bar(a, b, c) print(a, b, c) return 4, 8, 15, 16, 23, 42 end x, y = bar('zaphod') --> "zaphod nil nil" -- x = 4, y = 8, 其餘值被忽略 -- 函式與其他型別一樣為一等公民 -- 同樣有 local/global 之分 -- 像 Javascript 一樣定義 function f(x) return x * x end f = function (x) return x * x end print 'Hello World!' -- 只有一個`字串`引數時可省略括號 ---------- - 3. 表(Table) ---------- -- 表是 Lua 中唯一的複合型別 -- 像 PHP 中的陣列或 Javascript 中的 Object 一樣 -- 可用作 list/dict/map -- 預設以字串作為 key t = {key1 = 'value1', key2 = false} -- 像 Javascript 一樣以 . 取值 print(t.key1) --> "value1" t.key3 = {} -- 加入新的鍵值對 t.key2 = nil -- 銷燬一組鍵值對 -- 理論上任何非 nil 的變數都可以作為 key u = {['@!#'] = 'qbert', [{}] = 1729, [6.28] = 'tau'} print(u[6.28]) --> "tau" a = u['@!#'] -- a = 'qbert' b = u[{}] -- b = nil;像 Javascript 一樣 {} 會建立新的物件 -- 因此不要用蛋疼的 key 值,老老實實用字串或數字 -- 同字串一樣,只有一個表作為函式的引數時可以省略括號 -- 為了一個括號增加閱讀難度,得不償失 function h(x) print(x.key1) end h{key1 = 'Sonmi~451'} --> "Sonmi~451" for key, val in pairs(u) do -- 像 Python 一樣的鍵值迭代 print(key, val) end -- 像 Javascript 一樣的全域性作用域 _G print(_G['_G'] == _G) --> true -- 省略 key 之後即可變身為 list -- 實際上是以遞增自然數為 key v = {'value1', 'value2', 1.21, 'gigawatts'} for i = 1, #v do -- 像 Bash 一樣,#v 表示列表長度 print(v[i]) -- 像 Matlab 一樣,列表索引從 1 開始 end ---------- - 3.1 Metatables & metamethods ---------- -- 元表(metatable)就是表的表,像 Javascript 的原型(prototype)一樣 -- 為表過載一些元方法(metamethods) f1 = {a = 1, b = 2} f2 = {a = 2, b = 3} -- s = f1 + f2 為錯 mm = {} function mm.__add(x, y) sum = {} sum.a = x.a + y.a sum.b = x.b + y.b return sum end setmetatable(f1, mm) setmetatable(f2, mm) -- 實際呼叫 f1 的 metatable 中的 __add(f1, f2) -- 只為 f1 設定元表也可以 s = f1 + f2 -- s = {a = 3, b = 5} -- s2 = s + s 為錯,s 未定義元表 -- __index 元方法過載表中 key 的提取符號 `.` defaultFavs = {animal = 'gru', food = 'donuts'} myFavs = {food = 'pizza'} setmetatable(myFavs, {__index = defaultFavs}) food = myFavs.food -- Lua 中的值都具有元方法,只有 Table 可以過載 -- 所有元方法如下 -- __add(a, b) for a + b -- __sub(a, b) for a - b -- __mul(a, b) for a * b -- __div(a, b) for a / b -- __mod(a, b) for a % b -- __pow(a, b) for a ^ b -- __unm(a) for -a -- __concat(a, b) for a .. b -- __len(a) for #a -- __eq(a, b) for a == b -- __lt(a, b) for a < b -- __le(a, b) for a <= b -- __index(a, b) <fn or a table> for a.b -- __newindex(a, b, c) for a.b = c -- __call(a, ...) for a(...) ---------- - 3.2 類風格的 Table 與繼承 ---------- -- 像 Javascript 一樣並沒有內建 Class -- 但可以通過 Table `{}` 實現 Dog = {} -- 1. function Dog:new() -- 2. newObj = {sound = 'woof'} -- 3. self.__index = self -- 4. return setmetatable(newObj, self) -- 5. end function Dog:makeSound() -- 6. print('I say ' .. self.sound) end mrDog = Dog:new() -- 7. mrDog:makeSound() --> "I say woof" -- 1. Dog 像類但實際是 Table -- 2. Dog:new(...) := Dog.new(self, ...) -- 3. newObj 作 Dog 的例項 -- 4. self 是 Lua 中預設的引數,在這裡 self = Dog -- 繼承的時候可以改變 -- self.__index 與 self 的元方法 __index 不是一回事 -- self = {__index = self, metatable = {__index = ...}} -- 5. setmetatable(newObj, self) 相當於 setmetatable(newObj, {__index = self}) -- 賦予例項所有類方法 -- 6. 同 2. -- 7. mrDog = Dog.new(Dog) -- 繼承 LoudDog = Dog:new() function LoudDog:makeSound() s = self.sound .. ' ' print(s .. s .. s) end seymour = LoudDog:new() seymour:makeSound() --> "woof woof woof" ---------- - 4. 模組 ---------- -- 以下來自檔案 mod.lua local M = {} local function sayMyName() print('Hrunkner') end function M.sayHello() print('Why hello there') sayMyName() end return M -- 以上 -- 回到主檔案 local mod = require('mod') -- 執行 mod.lua 中的程式碼 -- 操作同下 local mod = (function() -- 像 Javascript 一樣 --[[ mod.lua 中的程式碼 ]]-- end)() mod.sayHello() --> "Why hello there" mod.sayMyName() --> 錯!sayMyName() 是 mod.lua 中的區域性變數 -- require 返回的值將被快取 -- 即使多次呼叫 require 被呼叫檔案也只執行一次 -- mod2.lua 包含 print("mod2") local a = require("mod2") --> "mod2" local b = require("mod2") -- 不輸出, 實際為 b = a -- dofile 是不快取的版本的 require dofile("mod2") --> "mod2" dofile("mod2") --> "mod2" -- loadfile 讀取檔案但不執行 -- 勘誤:f = loadfile('mod2'),需加字尾名,否則找不到檔案 f = loadfile('mod2.lua') f() --> "mod2" -- loadstring 讀取程式碼字串 f = loadstring("print('Lua is cool!')") f() --> "Lua is cool!" ---------- - 5. 參考,略 ---------- |
後記:
感覺 Lua 才應該是學完 C 語言之後最先學習的語言,因為它本身就是一個非常優秀的純粹由 C 語言完成的專案,尤其是對於非計算機專業出身又想要學習計算機原理相關的東西,甚至可以嘗試閱讀 Lua 原始碼;因為其內容簡潔而又五臟俱全,相比於其它高階語言對基本資料型別的複雜操作、複雜的語法結構等,Lua 15 分鐘入門應該會比《21天精通XXX》更現實一些吧:)
。
– END –