APISIX Lua 编码风格指南

    1. if a then
    2. ngx.say("hello")
    3. end

    你可以在使用的编辑器中把 tab 改为 4 个空格来简化操作。

    空格

    在操作符的两边,都需要用一个空格来做分隔:

    1. --No
    2. local i=1
    3. local s = "apisix"
    1. --Yes
    2. local i = 1
    3. local s = "apisix"

    空行

    不少开发者会在行尾增加一个分号:

    1. --No
    2. if a then
    3. ngx.say("hello");
    4. end;

    增加分号会让 Lua 代码显得非常丑陋,也是没有必要的。

    另外,不要为了显得“简洁”节省代码行数,而把多行代码变为一行。这样会在定位错误的时候不知道到底哪一段代码出了问题:

    1. --No
    2. if a then ngx.say("hello") end
    1. --Yes
    2. if a then
    3. ngx.say("hello")
    4. end

    函数之间需要用两个空行来做分隔:

    1. --No
    2. local function foo()
    3. end
    4. local function bar()
    5. end
    1. --Yes
    2. local function foo()
    3. end
    4. local function bar()
    5. end

    如果有多个 if elseif 的分支,它们之间需要一个空行来做分隔:

    1. --No
    2. if a == 1 then
    3. foo()
    4. elseif a== 2 then
    5. bar()
    6. elseif a == 3 then
    7. run()
    8. else
    9. error()
    10. end
    1. --Yes
    2. if a == 1 then
    3. foo()
    4. elseif a== 2 then
    5. bar()
    6. elseif a == 3 then
    7. run()
    8. else
    9. error()
    10. end
    1. --No
    1. --Yes
    2. return limit_conn_new("plugin-limit-conn", conf.conn, conf.burst,
    3. conf.default_conn_delay)

    在换行对齐的时候,要体现出上下两行的对应关系。

    就上面示例而言,第二行函数的参数,要在第一行左括号的右边。

    如果是字符串拼接的对齐,需要把 .. 放到下一行中:

    1. --Yes
    2. return limit_conn_new("plugin-limit-conn" .. "plugin-limit-conn"
    3. .. "plugin-limit-conn")
    1. --Yes
    2. return "param1", "plugin-limit-conn"
    3. .. "plugin-limit-conn")

    变量

    应该永远使用局部变量,不要使用全局变量:

    1. i = 1
    2. s = "apisix"
    1. --Yes
    2. local i = 1
    3. local s = "apisix"

    变量命名使用 snake_case(蛇形命名法) 风格:

    1. --No
    2. local IndexArr = 1
    3. local str_Name = "apisix"
    1. --Yes
    2. local index_arr = 1
    3. local str_name = "apisix"

    对于常量要使用全部大写:

    1. --No
    2. local max_int = 65535
    3. local server_name = "apisix"
    1. --Yes
    2. local MAX_INT = 65535
    3. local SERVER_NAME = "apisix"

    表格/数组

    使用 table.new 来预先分配数组:

    1. --No
    2. local t = {}
    3. for i = 1, 100 do
    4. t[i] = i
    5. end
    1. --Yes
    2. local new_tab = require "table.new"
    3. local t = new_tab(100, 0)
    4. for i = 1, 100 do
    5. t[i] = i
    6. end
    1. --No
    2. local t = {1, 2, nil, 3}

    如果一定要使用空值,请用 ngx.null 来表示:

    1. --Yes
    2. local t = {1, 2, ngx.null, 3}

    不要在热代码路径上拼接字符串:

    1. --Yes
    2. local new_tab = require "table.new"
    3. local t = new_tab(100, 0)
    4. for i = 1, 100000 do
    5. t[i] = "a"
    6. end
    7. local s = table.concat(t, "")

    函数

    函数的命名也同样遵循 snake_case(蛇形命名法):

    1. --No
    2. local function testNginx()
    3. end
    1. --Yes
    2. local function test_nginx()
    3. end

    函数应该尽可能早的返回:

    1. --No
    2. local function check(age, name)
    3. local ret = true
    4. if age < 20 then
    5. ret = false
    6. end
    7. if name == "a" then
    8. ret = false
    9. end
    10. -- do something else
    11. end
    1. --Yes
    2. local function check(age, name)
    3. if age < 20 then
    4. end
    5. if name == "a" then
    6. return false
    7. end
    8. -- do something else
    9. return true
    10. end

    模块

    所有 require 的库都要 local 化:

    1. --No
    2. local function foo()
    3. local ok, err = ngx.timer.at(delay, handler)
    4. end
    1. --Yes
    2. local timer_at = ngx.timer.at
    3. local function foo()
    4. local ok, err = timer_at(delay, handler)
    5. end

    为了风格的统一,requirengx 也需要 local 化:

    1. --No
    2. local core = require("apisix.core")
    3. local timer_at = ngx.timer.at
    4. local function foo()
    5. local ok, err = timer_at(delay, handler)
    6. end
    1. --Yes
    2. local ngx = ngx
    3. local require = require
    4. local core = require("apisix.core")
    5. local timer_at = ngx.timer.at
    6. local function foo()
    7. local ok, err = timer_at(delay, handler)
    8. end

    对于有错误信息返回的函数,必须对错误信息进行判断和处理:

    1. --No
    2. local sock = ngx.socket.tcp()
    3. local ok = sock:connect("www.google.com", 80)
    4. ngx.say("successfully connected to google!")
    1. --Yes
    2. local sock = ngx.socket.tcp()
    3. local ok, err = sock:connect("www.google.com", 80)
    4. if not ok then
    5. ngx.say("failed to connect to google: ", err)
    6. return
    7. end
    8. ngx.say("successfully connected to google!")
    1. --No
    2. local function foo()
    3. local ok, err = func()
    4. if not ok then
    5. return false
    6. end
    7. return true
    8. end
    1. --Yes
    2. local function foo()
    3. local ok, err = func()
    4. if not ok then
    5. return false, "failed to call func(): " .. err
    6. end
    7. return true