Lua程式碼規範
每個語言都有他自己的程式碼規範,如何寫好一個易懂又美觀的程式碼,下面我們來學習一下。
空行
加空行:
-
函式之間都要加空行;
-
函式內部程式碼概念與邏輯之間,邏輯段落小節之間,都應該加空行;
-
註釋行之前。
不加空行:
-
在一個函式體內,邏揖上密切相關的語句之間不加空行;
-
多行註釋解釋引數的時候,註釋之間不加空行。
空格
加空格:
-
”and“,”or“等關鍵字前後留一個空格,便於辨析;
-
逗號”,“後面要留一個空格;
-
賦值操作符、比較操作符、算術操作符如”=“、 “==“、”~=“、”>=“、”<=“、”>“、”<“、”+“、”-“、”*“、”/“、”%“、”^“,等二元操作符的前後應當加空格;
-
if、for、while等關鍵字之後如果要加左括號”(“,關鍵字與左括號之間應留一個空格,以突出關鍵字;
不加空格:
-
函式名之後不要留空格,緊跟左括號”(“;
-
左括號”(” 向後緊跟,緊跟處不留空格;
-
右括號”)“、逗號”,“、分號”;“,向前緊跟,緊跟處不留空格;
-
字串連線符”..“前後不加空格;
-
“:“,”.“,”[“,”]“這類操作符前後不加空格;
程式碼示例
-
a > b and a or b -- 良好的風格
-
a > b and a or b -- 不良的風格
-
local a, b, c, max -- 良好的風格
-
local a,b,c,max -- 不良的風格
-
if a > b then -- 良好的風格
-
max = a
-
end
-
if a>b then max=a end -- 不良的風格
-
data = dataTable[index] -- 良好的風格
-
data = dataTable [ index ] -- 不良的風格
-
function(posX, posY) -- 良好的風格
-
function (posX,posY) -- 不良的風格
長行拆分
-
程式碼行最大長度宜控制在70至80個字元以內。程式碼行不要過長,否則眼睛看不過來,也不便於列印;
-
長表示式要在低優先順序操作符處拆分成新行,操作符放在新行之首(以便突出操作符)。
-
-- 良好的風格
-
local newBuindingBtn = UI.newButton({
-
text = btnName,
-
x = self.x,
-
y = self.y,
-
parent = self,
-
style = {
-
normal = ResConfig.png.commonBtnBlue
-
}
-
})
-
-- 不良的風格
-
local newBuindingBtn = UI.newButton({text = btnName,x = self.x,y = self.y,parent = self, style = {normal = ResConfig.png.commonBtnBlue}})
-
-- 良好的風格
-
if veryLongerVariable1 >= veryLongerVariable2
-
and veryLongerVariable3 <= veryLongerVariable5
-
and veryLongerVariable4 <= veryLongerVariable6 then
-
doo()
-
end
-
-- 不良的風格
-
if veryLongerVariable1 >= veryLongerVariable2 and veryLongerVariable3 <= veryLongerVariable5 and veryLongerVariable4 <= veryLongerVariable6 then
-
doo()
-
end
命名規則
共性規則
-
命名應當直觀且可拼讀,可望文知意;
-
識別符號的長度應當符合“min-length && max-information”原則;
-
採用英文單詞或單詞組合,英文單詞不要複雜,但用詞需準確,切忌使用漢語拼音命名;
-
切勿為了避免命名過長而隨意擷取單詞,以丟失可讀性;
-
所有命名都不要與-x已有的命名風格衝突,例如不要以CC,UI開頭;
檔案命名
-
所有Lua檔案的命名時使用大駝峰法;
-
根據檔案的特性,一般以檔案裡的模組名或者類名作為同名檔名;
-
確定命名前,請檢查下,不要跟其他檔案同名;
-
CCArmature.lua -- 不良的風格
-
UILayout.lua -- 不良的風格
類的命名
-
所有類命名時使用大駝峰法;
-
類名一般由”名詞”或”多名詞”組成,不要簡寫;
-
根據類的特性,加上相關的字尾或者字首;
-
管理類 Manager
-
快取類 Cache
-
控制類 Controller
-
模組 Module
-
網路類 Proxy
變數命名
-
使用 “名詞” 或是 “形容詞+名詞” 命名;
-
使用小駝峰法命名;
-
為了可讀性,儘量避免變數名中出現標號,如value1, value2;
-
不要出現僅靠部分字母大小寫區分的相似的變數;
-
除非是區域性變數功能等價全域性變數,不然區域性變數不要與已有的全域性變數同名;
-
儘量不要使用已有的類名作為變數名;
-
local data -- 良好的風格
-
local oldData -- 良好的風格
-
local newData -- 良好的風格
-
local pairs = pairs -- 良好的風格
-
local posx,posX -- 不良的風格
-
local btn1,btn2 -- 不良的風格
-
local TABLE = {} -- 不良的風格
-
local uILabel -- 不良的風格
類的成員變數
-
類的成員變數以”self.”開頭,以區分於區域性變數;
例如:
-
function init()
-
self.mainPanel = false -- 常用格式
-
topPanel = false -- 這樣是全域性變數,佔用全域性資源,而且難以區分於區域性變數
-
...
-
end
全域性變數
全域性變數使用雙下劃線(““)開頭以及結尾,中間的命名以名詞拼接,或”形容詞+名詞”拼接,不同單詞之間用(”“)隔開; 例如: _VERSION_CODE = "1.0.0.0"
區域性變數
M常用做模組裡面表示模組本身
-
module("MainGame.Module.IntegrationTest.MapModule",package.seeall)
-
local M = class(SceneView,"MapScene")
-
資料的初始化
-
function M:init()
-
...
-
end
-
...
-
return M
-
引用進來的類或模組,用大駝峰法命名,引用路徑統一帶括號;
-
module(“MainGame.Module.IntegrationTest.MapModule”,package.seeall)
-
local M = class(SceneView,”MapScene”)
-
local Surface = require(“xx.xx”)
-
local TestButtonPanel = require(“xx”)
臨時變數
-
常用下劃線”_”作為可以忽略的變數
-
for _,v in ipairs(t) do print(v) end
-
i,k,v,t --常做臨時變數
-
for k,v in pairs(t) ... end
-
for i,v in ipairs(t) ... end
-
mt.__newindex = function(t, k, v) ... end
常量,事件名的命名
常量,事件名所用單詞均大寫,單詞用下劃線(‘_‘)分割;
例如:
-
-- 常量 預設寬度
-
LIST_DEFAULT_WIDTH = 100
-
-- 事件 新增到場景
-
ADDED_TO_STAGE = getId()
列舉的命名
-
列舉名命名,與類名命名一致;
-
列舉值命名,與常量,事件名的命名一致;
例如:
-
ControllerViewType = {
-
SCENE = "SCENE",
-
PANEL = "PANEL",
-
POP = "POP",
-
}
檔案組織
檔案描述
-
檔案開頭加上此檔案的簡要功能作用描述;
-
-- MapModule.lua
-
--Author:xx
-
--Email:xx@flamingo-inc.com
-
--20xx年x月x日 xx:xx
-
--Using:建立地圖
-
module("MainGame.Module.IntegrationTest.MapModule",package.seeall)
-
...
檔案中變數的定義
如果在檔案中需要多次使用的某些匯入檔案,可以在檔案開頭用區域性變數儲存匯入資訊,而不是在每次使用的時候都重新匯入一次;
-
...
-
local Surface = require("xx.xx")
-
local TestButtonPanel = require("xx")
-
function M:xx()
-
local testBtn = TestButtonPanel.newCC()
-
...
-
end
-
function M:yy()
-
local panel = TestButtonPanel.newCC()
-
local surface = Surface.newCC()
-
...
-
end
-
...
類變數的定義
-
類中的成員變數需要在init中先宣告,並賦予初始值,不允許不宣告直接使用;
函式引數的定義
-
所有函式的引數都用統一的params做引數,並加入如下格式的註釋:
-
--[[
-
普通按鈕 可縮放 scale9
-
@param #string text 按鈕名稱
-
@param #table style 按鈕樣式
-
]]
-
function UI.newButtonScale9(params)
-
...
-
end
函式的定義規則
-
函式的行數過長(大於 100 行)時,儘量拆分為多個子函式;
-
函式中一些晦澀的部分,一定要加上註釋;
註釋的使用
-
短小的註釋用–;
-
長註釋用–[[]];
編碼技巧
應該儘量使用local變數而非global變數
-
全域性變數實際是放入全域性表中,每次呼叫是用傳入變數名作為key去獲取,而local變數是直接通過lua的堆疊訪問的;
-
在能用區域性變數解決的地方,不要使用全域性變數,這點很容易被忽略;
-
多次重複使用的全域性介面,可以用區域性變數儲存下再使用;
-
比如需要多重遍歷操作一個大表:
-
for k1,v1 in pairs(tbl) do
-
for k2,v2 in pairs(v1) do
-
...
-
end
-
end
-
do
-
local pairs = pairs
-
for k1,v1 in pairs(tbl) do
-
for k2,v2 in pairs(v1) do
-
...
-
end
-
end
-
end
由於pairs是一個全域性變數應用的函式,所以寫法2在這裡有稍微效率上的提升,但要是單層遍歷的沒有這個效果了。
臨時變數的處理
-
字串的連線 .. 由於字串的管理機制,字串在使用..連線時,會產生新的物件。由於lua在VM內對相同的string永遠只保留一份唯一copy。
例如:
-
local description = ""
-
for i = 1,20 do
-
description = description.."xxx"
-
end
這樣會生成21份string的copy,但實際上我們只需要最後那一份 如果是輕量級的簡單連線還是可以使用的,因為影響不大,但要是大量的類似拼接,推薦使用string.format
類似於字串的管理機制,表也存在類似的臨時變數copy:
函式傳引數
-
function func({x,y})
-
...
-
end
這種傳參方式,每次都會生成一份copy,所以推薦以下的用法:
-
function func(x,y)
-
...
-
end
-
function func({posX = x, posY = y})
-
...
-
end
利用邏輯運算的短路效應
-
and or 的返回值是表示式中的左值或者右值,可用來簡化程式碼
-
function foo(arg)
-
arg = arg or "default"
-
...
-
end
但要注意當賦值為bool值時候,容易出bug
-
a = a or true -- 錯誤的寫法,當 a 明確寫為 false 的時候,也會被改變成 true 。
-
a = a ~= false -- 正確的寫法,當 a 為 nil 的時候,被賦值為 true ;而 false 則不變。
另外,巧妙使用 and or 還可以實現類似 C 語言中的 ?: 三元操作:
-
function max(a,b)
-
return a > b and a or b
-
end
這裡相當於 return (a > b) ? a : b;
程式碼建議
程式碼的除錯
用Luastudio工具除錯,代替Sublime除錯Lua程式碼;
複雜度和效能問題
寫程式碼時儘可能寫的簡單,考慮效能時先做好推斷,看看能提升多少,增加的複雜度以及造成的程式碼晦澀有多嚴重,然後再決定如何做;
函式的優化思考
-
開銷大的函式,呼叫次數低的話,可以不做優化;
-
開銷較小的函式,但呼叫頻率很高,則從如何降低呼叫頻率以及減少函式的開銷兩個角度去思考優化;
提交程式碼的檢查
提交程式碼前,在svn commit中驗證提交的程式碼,去掉或註釋掉無關的程式碼,保證提交的程式碼無誤;
表結構的引用
儘量減少表中的成員是另個表的引用;