2023年政策修订增补工作正在进行中,欢迎参与!
  • Moegirl.ICU:萌娘百科流亡社群 581077156(QQ),欢迎对萌娘百科运营感到失望的编辑者加入
  • Moegirl.ICU:账号认领正在试运行,有意者请参照账号认领流程

使用者: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 的取餘數運算符為 %,冪運算為 ^

「不等於」運算符為 ~=。邏輯運算符為 andornot

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