Skip to content

Instantly share code, notes, and snippets.

@czlc
Last active January 4, 2018 07:59
Show Gist options
  • Save czlc/4eb8d65eea94d2dbba6d534367e6e436 to your computer and use it in GitHub Desktop.
Save czlc/4eb8d65eea94d2dbba6d534367e6e436 to your computer and use it in GitHub Desktop.

Revisions

  1. czlc renamed this gist Jan 4, 2018. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. czlc created this gist Jan 4, 2018.
    361 changes: 361 additions & 0 deletions test.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,361 @@
    # Lua 代码风格指南

    ## 格式化

    * 行首使用4字母缩进(Lua 推荐的是2字母)
    * 行长度不要超过80个字符
    * 不要用分号避免换行
    ```lua
    -- bad
    local whatever = 'sure';
    a = 1; b = 2

    -- good
    local whatever = 'sure'
    a = 1
    b = 2
    ```
    * 不要因为代码块较短,就写成一行
    ```lua
    -- bad
    local print_table = function(t) for _,v in ipairs(t) do print(v) end end

    -- good
    local print_table = function(t)
    for _,v in ipairs(t) do
    print(v)
    end
    end
    ```
    * `{``}`,及所有运算符前后应留一个空格
    ```lua
    -- bad
    local test={one=1}
    local thing=1
    thing = thing-1
    thing = thing*1
    thing = 'string'..'s'

    --good
    local test = { one = 1 }
    local thing = 1
    thing = thing - 1
    thing = thing * 1
    thing = 'string' .. 's'
    ```
    * `(``)` 前后不留空格
    * 逗号后空一格
    * 代码块之间留一个空行
    ```lua
    -- bad
    if thing then
    -- ...stuff...
    end
    function derp()
    -- ...stuff...
    end
    local wat = 7

    -- good
    if thing then
    -- ...stuff...
    end

    function derp()
    -- ...stuff...
    end

    local wat = 7
    ```
    * 字符串推荐使用双引号(")

    ## 命名规则

    * 作用范围越大的变量、函数,名字应该越具体(即越长)

    * 文件、变量、函数名称遵循`snake_case`规则

    >> https://en.wikipedia.org/wiki/Snake_case
    ```lua
    -- bad
    local OBJEcttsssss = {}
    local thisIsMyObject = {}
    local this-is-my-object = {}

    local c = function()
    -- ...stuff...
    end

    -- good
    local this_is_my_object = {}

    local function do_that_thing()
    -- ...stuff...
    end
    ```

    * 常量名称使用全大写字母,单词之间用下划线分隔
    ```lua
    --good
    local MAX_COUNT = 200
    ```

    * 下划线开头的变量名保留给lua内部使用,如`_G``_ENV`

    * 使用单下划线表示忽略的变量
    ```lua
    --good
    for _, name in pairs(names) do
    -- ...stuff...
    end
    ```

    * 类、模块名称遵循`PascalCase`规则
    >> https://en.wikipedia.org/wiki/PascalCase
    ```lua
    -- bad
    local date = require('date')
    local mongo_obj = require "mongo_obj"

    -- good
    local Date = require('date')
    local MongoObj = require "mongo_obj"
    ```

    ## 特性

    * 不要使用隐式类型转换
    ```lua
    local input_value = '4'

    -- bad
    local total_score = review_score .. ''
    local val = input_value * 1

    -- good
    local total_score = tostring(review_score)
    local val = tonumber(input_value)
    ```

    * 除了错误处理分支,尽量不用`debug`

    ## 变量

    * 变量声明时总是使用`local`, 避免产生全局变量
    * 不要定义不使用的变量;忽略的变量命名为`_`
    * 不要使用未定义变量
    * 在作用域的顶部给变量赋值,避免随用随取

    ```lua
    -- bad
    for _, item in ipairs(items) do
    if item.score > player:get_score() then
    -- do something
    end
    end

    -- good
    local score = player:get_score()
    for _, item in ipairs(items) do
    if item.score > score then
    -- do something
    end
    end
    ```

    * 合理减小变量的作用域
    ```lua
    -- bad
    local v, x, y, z
    if condition then
    x = u2*v3-u3*v2
    y = u3*v1-u1*v3
    z = u1*v2-u2*v1
    v = {x,y,z}
    end

    -- good
    local v
    if condition then
    local x = u2*v3-u3*v2
    local y = u3*v1-u1*v3
    local z = u1*v2-u2*v1
    v = {x,y,z}
    end
    ```

    ## 函数

    * 函数声明时总是使用`local`, 避免产生全局函数
    ```lua
    -- bad
    function foo()
    -- stuff
    end

    -- good
    local function foo()
    -- stuff
    end
    ```

    * 优先使用函数语法;避免产生匿名函数
    ```lua
    -- bad
    local nope = function(name, options)
    -- ...stuff...
    end

    -- good
    local function yup(name, options)
    -- ...stuff...
    end
    ```

    * 早失败,早返回; 减少嵌套层次;
    ```lua
    -- bad
    local function is_good_name(name)
    if #name >= 3 then
    if #name <= 30 then
    if not string.match(name, "%u") then
    return true
    end
    end
    end

    return false
    end

    -- good
    local function is_good_name(name, options, args)
    if #name < 3 or #name > 30 or string.match(name, "%u") then
    return false
    end

    return true
    end
    ```

    * 函数循环复杂度尽量低于10,不应超过15
    >> 循环复杂度定义: https://zh.wikipedia.org/wiki/%E5%BE%AA%E7%92%B0%E8%A4%87%E9%9B%9C%E5%BA%A6
    ##
    * 建议优先使用`OOP`模式设计系统
    * 类的私有成员函数名字使用下划线开头
    * 模块不要直接返回非基类
    * 类的对象应使用同一个元表
    ```lua
    -- bad
    -- foo.lua
    local mt = {}
    function mt:_do_foo()
    -- stuff
    end

    function mt:foo()
    -- stuff
    self:_do_foo()
    -- stuff
    end

    local M = {}
    function M.new_obj()
    local obj = {
    -- stuff
    }
    return setmetatable(obj, {__index=mt})
    end
    return M

    -- good
    -- foo.lua
    local mt = {}
    mt.__index = mt
    function mt:_do_foo()
    -- stuff
    end
    function mt:foo()
    -- stuff
    self:_do_foo()
    -- stuff
    end

    local M = {}
    function M.new_obj()
    local obj = {
    -- stuff
    }
    return setmetatable(obj, mt)
    end
    return M
    ```

    * 外部不要直接访问/修改类的成员变量; 如果外部需要频繁访问类的成员变量,需要考虑一下类的内聚性。
    ```lua
    -- bad
    local obj = new_obj()
    print(obj.score)
    obj.score = 5

    -- good
    local obj = new_obj()
    print(obj:get_score())
    obj:set_score(5)
    ```

    ## 模块

    * 模块总是返回一个`table`
    * 建议模块内待返回的`table`使用`local M = {}`声明方式

    ## 头文件

    * 通过`require`引用的模块,应该按照通用性由高到底排序
    * 通用模块、业务模块、服务内模块之间应使用空行分隔

    ```lua
    -- bad
    local RoomApi = require "room_api"
    local RoomConst = require "war_room.const"
    local Env = require "global"
    local Date = require "date"
    local Log = require "log"

    -- good
    local Log = require "log"
    local Date = require "date"

    local RoomApi = require "room_api"
    local RoomConst = require "war_room.const"

    local Env = require "global"
    ```


    ## skynet

    * 不要在循环中调用别的服务;`call``send`都应避免
    ```lua
    -- bad
    for _, item in ipairs(items) do
    Skynet.call(addr, "lua", "add_item", {item_id=item.item_id})
    end

    -- good
    local request = {}
    for _, item in ipairs(items) do
    table.insert(request, {item_id=item.item_id})
    end
    Skynet.call(addr, "lua", "add_items", request)
    ```

    * 不要在循环中进行`io`操作

    ## 参考

    1. [Lua Style [email protected]](http://lua-users.org/wiki/LuaStyleGuide)
    2. [Lua Style [email protected]/Olivine-Labs](https://github.com/Olivine-Labs/lua-style-guide/blob/master/README.md)