使用者:Greykid/參考手冊/Lua 語言入門
《真·女神轉生》大係數據編纂和樣式設計統一模塊 「模塊:Psk」 的參考手冊。操作細則和貢獻方式,請進入《真·女神轉生》大系編輯者群(832689630)尋求進一步幫助。
本文概述使用 Lua 程式語言編寫 Scribunto MediaWiki 模塊化程序的基礎知識。
初學編程
本文默認讀者已經學會至少一種程式語言(C++、Python、Java 或 Visual Basic),有一定的編程經驗。如果沒有學過編程,請先行閱讀普通高中信息技術選修1《算法與程序設計》了解編程原理。
熟練使用 Lua 編寫模塊,還需要一定的前端基礎(HTML/CSS/Javascript)。
Lua 語言概述
基礎
Lua 對大小寫敏感。
Lua 是動態類型語言,變量不需要類型定義,只需要為變量賦值。值可以存儲在變量中,作為參數傳遞或結果返回。
Lua 中的基本數據類型:nil(無效值)、boolean、number(雙精度浮點數)、string、function、table(列表)。
Lua 提供運行時字符串與數字之間的自動轉換。
Lua 中的變量全是全局變量,那怕是語句塊或是函數裡,除非用 local 顯式聲明為局部變量。局部變量的作用域為從聲明位置開始到所在語句塊結束。
變量的默認值均為 nil。
Lua 的字符串可以用單引號,也可以用雙引號包括。
布爾類型只有 nil 和 false 是 false。數字 0、''、'\0' 都是 true。
Lua 語言編寫注釋,在行注釋前添加兩個減號:-- 此为注释
運算符
Lua 的取餘數運算符為 %,冪運算為 ^。
「不等於」運算符為 ~=。邏輯運算符為 and、or、not。
Lua 中 and 和 or 都是短路求值(short-cur evaluation),也就是說,它們只會在需要時才去評估第二個操作數。
使用 .. 連接兩個字符串,使用一元運算符 # 返回字符串或 table 的長度。
運算符優先級:
^ not - (unary) * / % + - .. < > <= >= ~= == and or
條件和循環語句
if 條件語句:
if (condition1) then
...
elseif (condition2) then
...
elseif (condition3) then
...
else
...
end
while 循環語句:
while (condition) do
...
end
break 跳出最內層的循環。
for 循環語句:
for var = exp1, exp2, exp3, ... do
...
end
for i, v in pairs(list) do
...
end
for i, v in ipairs(list) do
...
end
注意:ipairs 這個迭代器只能遍歷所有數組下標的值,這是前提,也是和 pairs 的最根本區別,也就是說如果 ipairs 在迭代過程中是會直接跳過所有手動設定 key 值的變量。
特別注意一點,和其他多數語言不同的地方是,Lua 的下標是從 1 開始的。
table
Lua 的 table 其實就是一個字典(Key-Value)數據結構。
JackFrost = {
age = 101,
namezh = '傑克霜精',
[3.14] = 'Pi',
['Black Frost'] = { namezh = '邪惡霜精', namejp = 'ジャアクフロスト', isGay = false }
}
Lua 語言本身採用一種語法糖,支持以 a.name 的形式表示 a['name']。
函數
Lua 的函數和 Javascript 的很像。
function fib(n)
if n < 2 then return 1 end
return fib(n - 2) + fib(n - 1)
end
Lua 中可以將函數作為參數傳遞給函數。
function newCounter()
local i = 0
return function() -- 匿名函数
i = i + 1
return i
end
end
c1 = newCounter()
print(c1()) --> 1
print(c1()) --> 2
function myPower(x)
return function(y) return y^x end
end
power2 = myPower(2)
power3 = myPower(3)
print(power2(4)) -- 4的2次方
print(power3(5)) -- 5的3次方
與 Python 語言類似,可以在一條語句上賦多個值。下面的代碼中,因為只有 3 個變量,所以第四個值被丟棄。函數也可以返回多個值。
name, age, isGay = "Jack Frost", 100, false, "Hee-Ho~"
function getUserInfo()
return "Jack Frost", 100, false, "Hee-Ho~"
end
name, age, isGay = getUserInfo()
在 Lua 中沒有函數「重載」的語法。但是,調用函數時參數可以少填或不填,此時未賦值的參數為 nil。
函數前面加上 local 就是局部函數。
多模塊
可以直接使用 require('model_name') 來載入另一個 lua 模塊。相當於將 require 語句處替換為另一個模塊的全部代碼。
local getGames = require('Module:Psk/Gamedata')
-- 以下为 Module:Psk/Gamedata 中的内容:
local games = { ... }
return { games = games }
接入 MediaWiki
Scribunto MediaWiki 使用 {{ #invoke: 模块名 | 主函数名 }} 調用模塊。
模塊編寫範例:
local p = {} -- p 是 package 的意思
function p.hello(frame)
return 'Hello, world!'
end
return p
模塊的命名空間一定要是「Module」或「模塊」。
Lua 語言本身為腳本語言。實現以類似模板的形式({{ #invoke: 模块名 | 主函数名 | 管道传参 }})調用模塊,需要藉助 模塊:Arguments。
local getArgs = require('Module:Arguments').getArgs
local p = {}
local function makeInvokeFunction(funcName)
return function (frame)
local args = getArgs(frame, {parentOnly = true})
return p[funcName](args)
end
end
p.foo = makeInvokeFunction('_foo')
function p._foo(args)
...
end
return p
更多
想了解更多 Lua 語言的複雜語法,參見 Lua 5.1 參考手冊。
Scribunto MediaWiki 提供的官方 Lua 編程文檔:Lua reference manual。