求闻百科:格式手册/Lua

本页使用了标题或全文手工转换,现处于简体转换模式
页面被全保护
求闻百科,共笔求闻

本方针列举了用Lua语言编写Scribunto模块应该遵守的一些规定。遵守这些规范有助于Lua代码更加可读、性能更佳并易于维护。

代码逻辑与算法

不要定义全局变量

在Lua中,定义变量(包括声明函数)时应该尽可能使用局部变量,避免定义全局变量。例如,下面这个例子就是不恰当的,

myconst = 32
function myutil(s)
  -- 一段代码
end

应当改成:

local myconst = 32
local function myutil(s)
  -- 一段代码
end

对于MediaWiki库中指定了使用全局变量的,则可以按照MediaWiki库函数中的操作。此外,暂时规定模块:No globals也是一个例外,该模块会通过修改_G的元表来防止定义全局变量,即通过修改全局变量本身来避免意外修改全局变量。

尽可能使用已有函数

很多模块需要实现的一些功能,没必要专门通过写函数来实现,而是尽可能使用已有的函数。例如,MediaWiki提供的mwModule:TableTools等元模块、libraryUtil库都提供了相当实用的函数。这些情况下应该尽可能使用已经提供好的函数,而不需要自己去定义一个新的。例如:

local function trim(s)
  return s:match "^%s+(.-)%s+$"
end

就完全可以写成:

local trim = mw.text.trim

对于很多模块都单独声明了,且没有已有函数提供该功能的,可以将其合并到新的或已有的元模块的函数中。

避免在Lua中展开模板或解析wiki文本

在Lua模板中,能用模块解决的,就不要调用模板。例如,在代码中,如需调用模板链接:{{navbox}},应该调用require 'Module:Navbox'._navbox,而不是frame:expandTemplate{name = 'Navbox', args = 参数}这样会快得多。

能直接使用frame:callParserFunctionframe:extensionTag的(以及某些情况确实需要调用frame:expandTemplate的),就不要使用frame:preprocess

能使用mw库中的函数解决的,就避免去调用解析器函数。例如,已经有tostring(mw.title.getCurrentTitle()),就不要去使用frame:callParserFunction('FULLPAGENAME'),更不要使用frame:preprocess '{{FULLPAGENAME}}'

严禁频繁连接字符串

有时候需要对输出的字符串逐个增加,例如:

local result = ''
for _, s in ipairs(my_list) do
  result = result .. '* ' .. s
end
return result

这种行为称为频繁连接字符串。这样每连接一次,都会创建新的字符串对象,然后将旧的字符串作为垃圾回收,影响性能。

如果需要多次追加字符串,应当使用表(数组),最后使用table.concat连接。此外,频繁往表(数组)的末尾处追加时,建议使用t[#t + 1] = v而非table.insert(t, v),这是因为Lua最原始的运算操作往往比调用函数更快。

local result = {}
for _, s in ipairs(my_list) do
  result[#result + 1] = '* ' .. s
end
return table.concat(result)

在本例中,还可以使用更加友好、更加灵活的mw.html库,例如:

local result = mw.html.create 'ul'
for _, s in ipairs(my_list) do
  result:tag 'li':wikitext(s)
end
return tostring(result)

区分普通模块与数据

有时候需要在模块内存储表形式的大量数据。这种情况下,应该将数据放在专门的模块页面中,然后在运行时使用mw.loadData而非require获取这些数据。与require相比,mw.loadData的优点在于,无论通过多少模板、模块运行多少次,mw.loadData在每个页面均只会运行和加载一次目标模块页面的数据,而不是每个模块都加载一次。这对含有大量数据的模块而言,性能非常高。

目前求闻百科有许多数据模块,例如Module:CGroup的子页面(公共转换组)、Module:RailSystems的子页面(轨道交通系统)等。这些数据模块都应该使用mw.loadData加载。

注意,使用mw.loadData加载的表是只读的,并且是通过元表来访问字段的。因此mw.loadData返回的对象不能写入任何字段(否则会出错),也不能使用table库中的函数或者#操作符。但是,常规的字段访问以及通过pairsipairs进行迭代仍然是正常的。

代码格式

空行

空行可以将代码清晰地分成多个部分。通常,多个函数之间应当空行。

空格

空格可以使得代码更加美观。以下情况下,建议空格

  • 运算符之间,例如c = a + b
  • 用逗号分隔的多个变量之间,例如tonumber('32', 7)return a, bfor k, v in pairs(t) do
    • 注意:函数名称和参数之间不空格,但紧接字符串字面量、省略括号的情况除外。如f(32)不建议写成f (32)print 'Hello'不建议写成print'Hello'
  • 单行注释的两个横线之后建议加一个空格。如代码后同一行内加入注释,两个横线之前建议加至少两个空格。

缩进

缩进可以使得代码层次清晰。虽然不像Python那样必要,但是没有缩进的代码以及缩进混乱的代码必然十分难读。

每一级缩进一般使用“制表符”(在代码编辑器中按键盘上的Tab键,手机版可能无法直接输入制表符,可以复制代码中已有的制表符)。尽管很多IDE都推荐使用空格代替制表符,但是在求闻百科不强求这么做。

此外,对于MediaWiki库的mw.html对象,可以在链式调用中根据层次逻辑调整缩进。

一个Lua页面内不允许混用不同类型(制表符、空格)缩进。要么全用空格,要么全用制表符。

注释

注释用于在代码中记录著作权协议、函数用法或提醒编辑者等内容,使得读者更加能够理解注释内容。注释可以用于:

  • 阐明函数的返回值类型和用途,以及参数的类型和用途
  • 将不再需要的代码注释掉。
  • 说明代码中的逻辑。

此外,注释不应当“说废话”。例如x = x + 1 -- 将x增加1是没有意义的。