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