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