APISIX Lua 编码风格指南
缩进
使用 4 个空格作为缩进的标记:
--Noif a thenngx.say("hello")end
--Yesif a thenngx.say("hello")end
你可以在使用的编辑器中把 tab 改为 4 个空格来简化操作。
空格
在操作符的两边,都需要用一个空格来做分隔:
--Nolocal i=1local s = "apisix"
--Yeslocal i = 1local s = "apisix"
空行
不少开发者会在行尾增加一个分号:
--Noif a thenngx.say("hello");end;
增加分号会让 Lua 代码显得非常丑陋,也是没有必要的。
另外,不要为了显得“简洁”节省代码行数,而把多行代码变为一行。这样会在定位错误的时候不知道到底哪一段代码出了问题:
--Noif a then ngx.say("hello") end
--Yesif a thenngx.say("hello")end
函数之间需要用两个空行来做分隔:
--Nolocal function foo()endlocal function bar()end
--Yeslocal function foo()endlocal function bar()end
如果有多个 if elseif 的分支,它们之间需要一个空行来做分隔:
--Noif a == 1 thenfoo()elseif a== 2 thenbar()elseif a == 3 thenrun()elseerror()end
--Yesif a == 1 thenfoo()elseif a== 2 thenbar()elseif a == 3 thenrun()elseerror()end
每行最大长度
每行不能超过 80 个字符,超过的话,需要换行并对齐:
--Noreturn limit_conn_new("plugin-limit-conn", conf.conn, conf.burst, conf.default_conn_delay)
--Yesreturn limit_conn_new("plugin-limit-conn", conf.conn, conf.burst,conf.default_conn_delay)
在换行对齐的时候,要体现出上下两行的对应关系。
就上面示例而言,第二行函数的参数,要在第一行左括号的右边。
如果是字符串拼接的对齐,需要把 .. 放到下一行中:
--Noreturn limit_conn_new("plugin-limit-conn" .. "plugin-limit-conn" .."plugin-limit-conn")
--Yesreturn limit_conn_new("plugin-limit-conn" .. "plugin-limit-conn".. "plugin-limit-conn")
--Yesreturn "param1", "plugin-limit-conn".. "plugin-limit-conn")
变量
应该永远使用局部变量,不要使用全局变量:
--Noi = 1s = "apisix"
--Yeslocal i = 1local s = "apisix"
变量命名使用 snake_case(蛇形命名法) 风格:
--Nolocal IndexArr = 1local str_Name = "apisix"
--Yeslocal index_arr = 1local str_name = "apisix"
对于常量要使用全部大写:
--Nolocal max_int = 65535local server_name = "apisix"
--Yeslocal MAX_INT = 65535local SERVER_NAME = "apisix"
表格/数组
使用 table.new 来预先分配数组:
--Nolocal t = {}for i = 1, 100 dot[i] = iend
--Yeslocal new_tab = require "table.new"local t = new_tab(100, 0)for i = 1, 100 dot[i] = iend
不要在数组中使用 nil:
--Nolocal t = {1, 2, nil, 3}
如果一定要使用空值,请用 ngx.null 来表示:
--Yeslocal t = {1, 2, ngx.null, 3}
字符串
不要在热代码路径上拼接字符串:
--Nolocal s = ""for i = 1, 100000 dos = s .. "a"end
--Yeslocal t = {}for i = 1, 100000 dot[i] = "a"endlocal s = table.concat(t, "")
函数
函数的命名也同样遵循 snake_case(蛇形命名法):
--Nolocal function testNginx()end
--Yeslocal function test_nginx()end
函数应该尽可能早的返回:
--Nolocal function check(age, name)local ret = trueif age < 20 thenret = falseendif name == "a" thenret = falseend-- do something elsereturn retend
--Yeslocal function check(age, name)if age < 20 thenreturn falseendif name == "a" thenreturn falseend-- do something elsereturn trueend
模块
所有 require 的库都要 local 化:
```lua--Nolocal function foo()local ok, err = ngx.timer.at(delay, handler)end
--Yeslocal timer_at = ngx.timer.atlocal function foo()local ok, err = timer_at(delay, handler)end
为了风格的统一,require 和 ngx 也需要 local 化:
--Nolocal core = require("apisix.core")local timer_at = ngx.timer.atlocal function foo()local ok, err = timer_at(delay, handler)end
--Yeslocal ngx = ngxlocal require = requirelocal core = require("apisix.core")local timer_at = ngx.timer.atlocal function foo()local ok, err = timer_at(delay, handler)end
错误处理
对于有错误信息返回的函数,必须对错误信息进行判断和处理:
--Nolocal sock = ngx.socket.tcp()local ok = sock:connect("www.google.com", 80)ngx.say("successfully connected to google!")
--Yeslocal sock = ngx.socket.tcp()local ok, err = sock:connect("www.google.com", 80)if not ok thenngx.say("failed to connect to google: ", err)returnendngx.say("successfully connected to google!")
自己编写的函数,错误信息要作为第二个参数,用字符串的格式返回:
--Nolocal function foo()local ok, err = func()if not ok thenreturn falseendreturn trueend
--Nolocal function foo()local ok, err = func()if not ok thenreturn false, {msg = err}endreturn trueend
--Yeslocal function foo()local ok, err = func()if not ok thenreturn false, "failed to call func(): " .. errendreturn trueend
