《真·女神转生》大系数据编纂和样式设计统一模块 “模块:Psk” 的参考手册。操作细则和贡献方式,请进入《真·女神转生》大系编辑者群(832689630)寻求进一步帮助。
本文概述使用 Lua 编程语言编写 Scribunto MediaWiki 模块化程序的基础知识。
本文默认读者已经学会至少一种编程语言(C++、Python、Java 或 Visual Basic),有一定的编程经验。如果没有学过编程,请先行阅读普通高中信息技术选修1《算法与程序设计》了解编程原理。
熟练使用 Lua 编写模块,还需要一定的前端基础(HTML/CSS/Javascript)。
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 开始的。
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 }
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。