求聞百科:格式手冊/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是沒有意義的。