User: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。