apisix/CODE_STYLE_CN.md

427 lines
6.6 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->
[English](CODE_STYLE.md)
# 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
```