lua代码规范
目录
命名
- 小写蛇形命名
    
- 文件和目录名
 - 本地变量,全局变量
g_开头 
 
local my_var = 0
g_my_var = 0
- 大写蛇形命名
    
- 全局常量,以
G_开头 
 - 全局常量,以
 
G_SERVER_ID = 1
- 全局枚举,以
E_开头且_TYPE结尾 
E_SERVER_TYPE = {
    LOGIN = 1,
    GAME = 2,
    GLOBAL = 3,
}
- bool类型变量,使用正向命名
    
-- bad local fail = false if not fail then -- do something end-- good local succ = true if succ then -- do something end 
排版
- 在逗号之后添加一个空格
 
-- bad
local t = {1,2,3}
-- good
lcoal t = {1, 2, 3}
- 在运算符、赋值符和连接符前后各添加一个空格
 
-- bad
local sum = 1+2
-- good
local sum = 1 + 2
- 如查不能突出前后对齐关系,则应该避免对齐声明
 
-- bad
local a        = 1
local var_name = 2
-- good
func(a,        b, c)
func(var_name, b, c)
- 函数调用,不能省略括号
 
-- bad
func a, b, c
-- good
func(a, b, c)
- 不同逻辑代码块之间要空行
 
-- bad
function remove(list, n)
    if n <= 0 then
          return 0
    end
    table.sort(list, function(a, b)
          return a.id < b.id
    end
    for i = 1, n do
         local sz = #list
         if sz  >  0 then
              table.remove(list, sz)    
         end
    end
    return 
end
-- good
function remove(list, n)
    if n <= 0 then
          return 
    end
    table.sort(list, function(a, b)
          return a.id < b.id
    end
    for i = 1, n do
         local sz = #list
         if sz  >  0 then
              table.remove(list, sz)    
         end
    end
end
- 统一table初始化风格
 
--bad
local t = m[id]
if t then
    t.cnt = t.cnt + 1
else
    t = { cnt = 1 }
    m[id] = t
end
-- good
local t = m[id]
if not t then
     t = { cnt = 0 }
     m[id] = t
end
t.cnt = t.cnt + 1
-- good
m[id] = m[id] or { cnt = 0 } 
local t = m[id]
t.cnt = t.cnt + 1
-- godd
setmetable(m, {__index = function(t, k) return {cnt = 0} end})
m[id].cnt = m[id].cnt + 1
设计
- 使用
_表示未被使用的变量 
-- good
local list = {1, 2, 3, ...}
for _, v in pairs(list) do
    print(v)
end
-- good
local _, n = string.gsub("aabbc", "a", "")
- 私有对象使用
_前缀命名 
local M= {}
function M:init()
  self.a = 0
     -- good
  self._b = 0 -- 私有变量
end
-- good
function M:_func()
end
return M
- 遍历配置表/数据库数据,v值尽量命名为
row 
-- good
for _, row in pairs(Config.ItemConfig) do
  ...
end
-- good
local row_list = db:find_all(...)
for _, row in pairs(row_list) do
  ...
end
- 尽早验证并返回
 
-- bad
function enter_room(role, room_id)
     local cfg = Config.RoomConfig[room_id]
     if cfg ~= nil then
          local ok = role:cost_item(cfg.cost_item)
          if ok then
               ....
               return true
          else
               return false
          end
     else
          return fasle
     end
     return false
end
-- good
function enter_room(role, room_id)
     local cfg = Config.RoomConfig[room_id]
     if cfg == nil then
          return false
     end
     local ok = role:cost_item(cfg.cost_item)
     if not ok then
          return false
     end
     ....
     return true
end
- 代码尽可能减少缩进 ```lua – bad if a ~= nil then if b ~= nil then – do someting end end
 
– good if a ~= nil and b ~= nil then – do someting end
* 尽可能使用`or`关键字,减少代码缩进
```lua
-- bad
local preOpen = ""
if v.preOpen then
     preOpen = v.preOpen
end
local preRepel = ""
if v.preRepel then
     preRepel = v.preRepel
end
-- good
local preOpen = v.preOpen or ""
local preRepel = v.preRepel or ""
- 与业务处理有强相关的函数,尽可能返回错误码
 
-- bad
function can_send_chat(role)
     -- 角色禁言
     local is_ban = role:is_chat_ban()
     if is_ban then
          return false
     end
     -- 聊天CD时间
     local now = os.time()
     if role.chat_cd > 0 and role.chat_cd < now then
          return false
     end
     return true
end
-- good
function can_send_chat(role)
     -- 角色禁言
     local is_ban = role:is_chat_ban()
     if is_ban then
          return E_ERR_TYPE.CHAT_BAN
     end
     -- 聊天CD时间
     local now = os.time()
     if role.chat_cd > 0 and role.chat_cd < now then
          return E_ERR_TYPE.CHAT_CD
     end
     return E_ERR_TYPE.SUCCESS
end
- 跨行定义table变量,需要在末尾添加
, 
-- bad
local t = {
     a = 1
}
-- good
local t = {
     a = 1,
}
-- bad
local t = {a = 1,}
-- good
local t = {a = 1}
- 变量类型不要混合nil和false的含义
 
--bad
function can_get_mail(mail, role)
     local now = os.time()
     if now >= mail.expire_ts then
          return
     end
     
     if role.create_ts > mail.create_ts then
          return
     end
     return true
end
--good
function can_get_mail(mail, role)
     local now = os.time()
     if now >= mail.expire_ts then
          return false
     end
     
     if role.create_ts > mail.create_ts then
          return false
     end
     return true
end
- 变量的作用域尽量小
 
-- bad
function upgrade_equip(role, equip_id)
     local equip_obj = role:get_equip(equip_id)
     local cfg = Config.EquipConfig[equip_id]
     if cfg == nil then
          return E_ERR_TYPE.CONIFG_ERR
     end
     return equip_obj:upgrade()
end
-- good
function upgrade_equip(role, equip_id)
     local cfg = Config.EquipConfig[equip_id]
     if cfg == nil then
          return E_ERR_TYPE.CONIFG_ERR
     end
     local equip_obj = role:get_equip(equip_id)
     return equip_obj:upgrade()
end
- 变量的作用域在多个代码块,需要顶行声明且用空行分隔
 
-- bad
function buy_item(role, item_id, count)
     local shop_obj = role.shop
     local is_shelf = shop_obj:is_item_shelf(item_id)
     if not is_shelf then
          return E_ERR_TYPE.SHOP_ITEM_OFF_SHELVES
     end
     local remain_count = shop_obj:get_remain_count(item_id)
     if remain_count < count then
          return E_ERR_TYPE.SHOP_BUY_COUNT_LIMIT
     end
     
     ....
end
-- good
function buy_item(role, item_id, count)
     local shop_obj = role.shop
     local is_shelf = shop_obj:is_item_shelf(item_id)
     if not is_shelf then
          return E_ERR_TYPE.SHOP_ITEM_OFF_SHELVES
     end
     local remain_count = shop_obj:get_remain_count(item_id)
     if remain_count < count then
          return E_ERR_TYPE.SHOP_BUY_COUNT_LIMIT
     end
     
     ....
end
- 非业务全局函数,文件名以变量名称定义,且方法以
.声明 
-- file: table.lua
function table.shuffle()
....
end
-- file: string.lua
function string.split()
....
end
- 批量操作的代码顺序,要与代码声明顺序保持一致
 
local M = {}
function M:init()
     self.a = 0
     self.b = 0
     self.c = 0
end
-- bad
function M:destroy()
     self.b = 0
     self.a = 0
     self.c = 0
end
-- good
function M:copy(right)
     self.a = right.a
     self.b = right.b
     self.c = right.c
end
return M
- 针对业务的全局函数
 - 文件名以xxx_helper的格式定义
 - 为了减少全局变量污染,只在需要使用的文件中加载xxx_helper ```lua – file: mail_helper.lua local M = {}
 
function M:send_mail(role_id, mail_id, …) end
– 其它声明的函数 return M
* 尽量不要在多层嵌套作用域中退出函数
```lua
function foo()
     if ... then
          if ... then
               -- bad
               return true
          end
     end
     for _, i in pairs(list) do
          for _, j in pairs(batch) do
               if ... then
                    -- bad
                    return false
               end
          end
     end
     return true
end
function foo()
     local result = false
     if ... then
          if ... then
               -- good
               result = true
          end
     end
     for _, i in pairs(list) do
          for _, j in pairs(batch) do
               if ... then
                    -- good
                    result = false
                    break
               end
          end
     end
     return result
end
- 使用goto减少是循环层次
    
-- bad for k, v in pairs(l) do if v.ok then -- do something end end 
for k, v in pairs(l) do
     if not v.ok then goto continue end
     -- do something
     ::continue::
end
- 不要直接在事件通知函数,处理业务 ```lua – bad function M:on_xx_timer() – do something here end
 
– good function M:do_foo() – do something here end function M:on_xx_timer() self:do_foo() end
* 逻辑与写数据分离
```lua
-- bad
function M:hero_upgrade()
     -- 升级功能是否开启
     -- 是否已最大等级
     -- 处理物品消耗
     -- ....
     -- 最后设置英雄等级
     self.hero_level = x
     logger.log("hero upgrade", x)
end
-- good
function M:set_hero_level(x)
     self.hero_level = x
     logger.log("hero upgrade", x)
end
function M:hero_upgrade()
     -- 升级功能是否开启
     -- 是否已最大等级
     -- 处理物品消耗
     self:set_hero_level(x, y)
end
注释
- 注释
--后,需要空格 
-- bad
local v = 1 --v is a number
-- good
local v = 1 -- v is a number
- 文件头
 
--- summary.
-- Description; this can extend over
-- several lines
-- @script xxx.lua
-- @author xxx
- 函数
 
--- split a string in two.
-- It is a specialized splitting operation on a string.
-- @param [type=string] s the string
-- @param [type=string] delim the delimiter (default space)
-- @return first part
-- @return second part
-- @usage local hello,world = split2("hello world")
funtion split(s, delim) .. end
....
end
@param 的参数类型
| 类型 | type | 
|---|---|
| 整数 | int | 
| 浮点数 | float | 
| 字符串 | string | 
| 函数 | function | 
| 表 | table | 
| 协程 | coroutine | 
| 指针 | userdata | 
- 数组&哈希表
 
--bad
function M:init() 
     self.battle_map = {}
     self.battle_list = {} 
end
-- good
function M:init() 
     -- <battle_id:int, battle_tb:table> battle_tb结构: self:new_battle_struct()
     self.battle_map = {}
     -- {v1:table, v2:table, ...} 元素结构: self:new_battle_struct()
     self.battle_list = {} 
end
function M:new_battle_struct()
    return {
          ... 
     }
end
缩写
 
 
原文:
https://lizijie.github.io/2022/06/05/lua%E4%BB%A3%E7%A0%81%E8%A7%84%E8%8C%83.html
作者github:
https://github.com/lizijie
PREVIOUS数值程序化 lua中的load运用