OpenResty/Lua 編碼指南/指南

很多開發語言都有自己的編碼規范,來告訴開發者這個領域內一些約定俗成的東西,讓大家寫的代碼風格保持一致,并且避免一些常見的陷阱。這對于新手來說是非常友好的,可以讓初學者快速準確地上手。比如 Python 的 PEP 80,就是其中的典范,幾乎所有的 Python 開發者都閱讀過這份 Python 作者執筆的編碼規范。

**讓開發者統一思想,按照規范來寫代碼,是一件非常重要的事情。**OpenResty 還沒有自己的編碼規范,有些開發者在提交 PR 后,會在代碼風格上被反復 review 和要求修改,消耗了大量本可避免的時間和精力。

其實,在 OpenResty 中,也有兩個可以幫你自動化檢測代碼風格的工具:luacheck 和 lj-releng。前者是 Lua 和 OpenResty 世界通用的檢測工具,后者則是 OpenResty 自己用 perl 寫的代碼檢測工具。

對我自己來說,我會在 VS Code 編輯器中安裝 luacheck 的插件,這樣在我寫代碼的時候就有工具來自動提示;而在項目的 CI 中,則是會把這兩個工具都運行一遍,比如:

luacheck -q lua./utils/lj-releng lua/*.lua lua/apisix/*.lua 

畢竟,多一個工具的檢測總不是壞事。

但是,這兩個工具更多的是檢測全局變量、每行長度等這些最基礎的代碼風格,離 Python PEP 80 的詳細程度還有遙遠的距離,并且也沒有文檔給你參考。

所以今天,我就根據自己在OpenResty 相關開源項目中的經驗,總結了一下 OpenResty 的編碼風格文檔,這個規范也和一些常見的 API 網關比如 Kong、APISIX 的代碼風格是一致的。

縮進

在 OpenResty 中,我們使用 4 個空格作為縮進的標記,雖然 Lua 并沒有這樣的語法要求。下面是錯誤和正確的兩段代碼示例:

--No
if a then
ngx.say("hello")
end--yes
if a thenngx.say("hello")
end

為了方便,你可以在使用的編輯器中,把 tab 改為 4 個空格,來簡化操作。

空格

在操作符的兩邊,都需要用一個空格來做分隔。下面是錯誤和正確的兩段代碼示例:

--No
local i=1
local s    =    "apisix"--Yes
local i = 1
local s = "apisix"

空行

不少開發者會把其他語言的開發習慣帶到 OpenResty 中來,比如在行尾增加一個分號:

--No
if a thenngx.say("hello");
end;

但事實上,增加分號會讓 Lua 代碼顯得非常丑陋,也是沒有必要的。同時,你也不要為了節省代碼的行數,追求所謂的“簡潔”,而把多行代碼變為一行。這樣做會讓你在定位錯誤的時候,不知道到底是哪一段代碼出了問題:

--No
if a then ngx.say("hello") end--yes
if a thenngx.say("hello")
end

另外,函數之間需要用兩個空行來做分隔:

--No
local function foo()
endlocal function bar()
end--Yes
local function foo()
endlocal function bar()
end

如果有多個 if elseif 的分支,它們之間也需要一個空行來做分隔:

--No
if a == 1 thenfoo()    
elseif a== 2 thenbar()    
elseif a == 3 thenrun()    
elseerror()
end--Yes
if a == 1 thenfoo()elseif a== 2 thenbar()elseif a == 3 thenrun()elseerror()
end

每行最大長度

每行不能超過 80 個字符,如果超過的話,需要你換行并對齊。并且,在換行對齊的時候,我們要體現出上下兩行的對應關系。就下面的示例而言,第二行函數的參數,要在第一行左括號的右邊。

--No 
return limit_conn_new("plugin-limit-conn", conf.conn, conf.burst, conf.default_conn_delay)--Yes
return limit_conn_new("plugin-limit-conn", conf.conn, conf.burst,conf.default_conn_delay)

如果是字符串拼接問題的對齊,則需要把 … 放到下一行中:

--No 
return limit_conn_new("plugin-limit-conn" ..  "plugin-limit-conn" .."plugin-limit-conn")--Yes
return limit_conn_new("plugin-limit-conn" .. "plugin-limit-conn".. "plugin-limit-conn")

變量

這一點我前面也多次強調過,我們應該永遠使用局部變量,不要使用全局變量:

--No
i = 1
s = "apisix"--Yes
local i = 1
local s = "apisix"

至于變量的命名,應該使用 snake_case 風格:

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

而對于常量,則是要使用全部大寫的形式:

--No
local max_int = 65535
local server_name = "apisix"--Yes
local MAX_INT = 65535
local SERVER_NAME = "apisix"

數組

在OpenResty中,我們使用table.new 來預先分配數組:

--No
local t = {}
for i = 1, 100 dot[i] = iend--Yes 
local new_tab = require "table.new"local t = new_tab(100, 0)for i = 1, 100 dot[i] = iend

另外注意,一定不要在數組中使用 nil:

--No
local t = {1, 2, nil, 3}

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

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

字符串

千萬不要在熱代碼路徑上拼接字符串:

--No
local s = ""
for i = 1, 100000 dos = s .. "a"
end--Yes
local t = {}
for i = 1, 100000 dot[i] = "a"
end
local s =  table.concat(t, "")

函數

函數的命名也同樣遵循 snake_case:

--No
local function testNginx()
end--Yes
local function test_nginx()
end

并且,函數應該盡可能早地返回:

--No
local function check(age, name)local ret = trueif age < 20 thenret = falseendif name == "a" thenret = falseend-- do something else return ret --Yes
local function check(age, name)if age < 20 thenreturn falseendif name == "a" thenreturn falseend-- do something else return true 

模塊

所有 require 的庫都要 local 化:

--No
local function foo()local ok, err = ngx.timer.at(delay, handler)
end--Yes
local timer_at = ngx.timer.atlocal function foo()local ok, err = timer_at(delay, handler)
end

為了風格的統一,require 和 ngx 也需要 local 化:

--No
local core = require("apisix.core")
local timer_at = ngx.timer.atlocal function foo()local ok, err = timer_at(delay, handler)
end--Yes
local ngx = ngx
local require = require
local core = require("apisix.core")
local timer_at = ngx.timer.atlocal function foo()local ok, err = timer_at(delay, handler)
end

錯誤處理

對于有錯誤信息返回的函數,我們必須對錯誤信息進行判斷和處理:

--No
local sock = ngx.socket.tcp()local ok = sock:connect("www.google.com", 80)ngx.say("successfully connected to google!")--Yes
local 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!")

而如果是自己編寫的函數,錯誤信息要作為第二個參數,用字符串的格式返回:

--No
local function foo()local ok, err = func()if not ok thenreturn falseendreturn true
end--No
local function foo()local ok, err = func()if not ok thenreturn false, {msg = err}endreturn true
end--Yes
local function foo()local ok, err = func()if not ok thenreturn false, "failed to call func(): " .. errendreturn true
end

原文

https://github.com/apache/apisix/blob/v1.3/CODE_STYLE.md

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/72638.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/72638.shtml
英文地址,請注明出處:http://en.pswp.cn/web/72638.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

數據結構 -- 二叉樹的存儲結構

二叉樹的存儲結構 順序存儲 #define MaxSize 100 struct TreeNode{ElemType value; //結點中的數據元素bool isEmpty; //結點元素是否為空 };//定義一個長度為MaxSize的數組t&#xff0c;按照從上至下、從左至右的順序依次完成存儲完全二叉樹中的各個節點 TreeNode t[MaxSi…

Linux系統移植篇(十一)Linux 內核啟動流程

要分析 Linux 啟動流程&#xff0c;同樣需要先編譯一下 Linux 源碼&#xff0c;因為有很多文件是需要編譯才 會生成的。首先分析 Linux 內核的連接腳本文件 arch/arm/kernel/vmlinux.lds&#xff0c;通過鏈接腳本可以 找到 Linux 內核的第一行程序是從哪里執行的。vmlinux.lds …

【Docker入門】構建推送第一個Docker映像

【Docker入門】構建推送第一個Docker映像 Build and Push the First Docker Image By JacksonML Docker的容器(Container)映像是輕量級的可執行獨立包&#xff0c;包含代碼、運行時、庫、環境變量以及配置文件&#xff0c;它對于運行軟件至關重要。注冊表可在團隊間分享映像。…

【eNSP實戰】(續)一個AC多個VAP的實現—將隧道轉發改成直接轉發

在 一個AC多個VAP的實現—CAPWAP隧道轉發 此篇文章配置的基礎上&#xff0c;將隧道轉發改成直接轉發 一、改成直接轉發需要改動的配置 &#xff08;一&#xff09;將連接AP的接口改成trunk口&#xff0c;并允許vlan100、101、102通過 [AC1]interface GigabitEthernet 0/0/8 …

SPI 總線協議

1、協議介紹 SPI&#xff0c;是英語 Serial Peripheral interface 的縮寫&#xff0c;顧名思義就是串行外圍設備接口。是 Motorola 首先在其 MC68HCXX 系列處理器上定義的。 SPI&#xff0c;是一種高速的&#xff0c;全雙工&#xff0c;同步的通信總線。主節點或子節點的數據在…

我愛學算法之——滑動窗口攻克子數組和子串難題(上)

現在來學習"滑動窗口"這一算法思想。 至于什么是"滑動窗口"呢&#xff1f;簡單來說就是同向雙指針&#xff1b;現在來通過題目來了解什么是"滑動窗口" 一、長度最小的子數組 題目鏈接&#xff1a;長度最小的子數組 題目解析 先來看題目&#…

ora-600 ktugct: corruption detected---惜分飛

接手一個oracle 21c的庫恢復請求,通過Oracle數據庫異常恢復檢查腳本(Oracle Database Recovery Check)腳本檢測之后,發現undo文件offline之后,做了resetlogs操作,導致該文件目前處于WRONG RESETLOGS狀態 嘗試恢復數據庫ORA-16433錯誤 SQL> recover datafile 1; ORA-00283:…

20. Excel 自動化:Excel 對象模型

一 Excel 對象模型是什么 Excel對象模型是Excel圖形用戶界面的層次結構表示&#xff0c;它允許開發者通過編程來操作Excel的各種組件&#xff0c;如工作簿、工作表、單元格等。 xlwings 是一個Python庫&#xff0c;它允許Python腳本與Excel進行交互。與一些其他Python庫&#x…

IIS 服務器日志和性能監控

Internet Information Services &#xff08;IIS&#xff09; 是 Microsoft 提供的一款功能強大、靈活且可擴展的 Web 服務器&#xff0c;用于托管網站、服務和應用程序。IIS 支持 HTTP、HTTPS、FTP、SMTP 和更多用于提供網頁的協議&#xff0c;因此廣泛用于企業環境。 IIS 的…

jenkins pipline 自動化測試

以下是一個典型的 Jenkins Pipeline 示例&#xff0c;用于執行自動化測試流程&#xff08;支持單元測試、集成測試、代碼質量掃描&#xff09;&#xff0c;包含多階段執行和測試結果處理&#xff1a; pipeline {agent anyenvironment {// 定義環境變量PROJECT_NAME "my-…

APP測試

一、APP測試范圍 功能測試性能測試&#xff1a;CPU、內存占用、啟動速度、流量、電量消耗、流暢度、穩定性專項測試&#xff1a;安裝卸載升級、push消息推送 、交叉事件測試 、用戶體驗測試 、兼容性測試 二、APP包發布方式及策略 分類&#xff1a; 內部發布渠道。如&#x…

12 File文件對象:創建、獲取基本信息、遍歷文件夾、查找文件;字符集的編解碼 (黑馬Java視頻筆記)

文章目錄 File >> 存儲數據的方案1. 認識File2. File操作2.1 創建File對象2.2 File操作1&#xff09;對文件對象的信息的操作2&#xff09;文件/文件夾的創建/刪除3&#xff09;??對文件夾的遍歷 3. 方法遞歸3.1 認識遞歸3.2 遞歸算法及其執行流程1) 案例&#xff1a;2…

oracle 基礎知識之 多表查詢

多表查詢定義&#xff1a;當查詢的數據并不是來源一個表時&#xff0c;需要使用多表連接操作完成查詢。多表連接查詢通過表之間的關聯字段&#xff0c;一次查詢出多個表的數據。多表查詢包括了等值連接、左連接、右連接、完全連接。 1.等值連接 等值連接也稱為簡單連接&#xf…

服務器防火墻根據什么特征來過濾數據包?

防火墻是服務器安全防護的第一道屏障&#xff0c;它的主要作用是監控、過濾和控制進出服務器的數據流量&#xff0c;防止惡意攻擊、非法訪問和數據泄露。防火墻通過分析數據包的特定特征來決定是否允許、拒絕或限制數據的傳輸。 服務器防火墻的基本工作原理&#xff1a; 防火墻…

Prims region.Views 為null

原因&#xff1a; 導航未完成或異步問題 解決方式&#xff1a;使用回調確認導航完成后再操作視圖 _regionManager.RequestNavigate("MonitorRegion", "MonitorView", nps, navigationResult > {if (navigationResult.Result true){var region _regio…

reconstruct_3d_object_model_for_matching例子

文章目錄 1.獲取om3文件2.準備可視化3.準備3D可視化4.讀取3D模型5.顯示成對注冊結果16.顯示成對注冊結果27.聯合注冊模型8.處理圖像8.1子采樣8.2 圖像計算與平滑8.3 三角測量 9.基于表面做3D匹配10.評估模型準確度10.1 在場景中找到模型10.2 計算模型和場景之間的距離 11.立體系…

軟件安全性測試的重要性和常用工具介紹,軟件測試服務公司推薦

在當今數字化快速發展的時代&#xff0c;軟件已經成為各行各業不可或缺的一部分。然而&#xff0c;隨著軟件系統的復雜性增加&#xff0c;安全性問題也愈發突出&#xff0c;因此軟件產品生產周期中安全測試必不可少。軟件安全性測試是指對軟件系統進行評估&#xff0c;以發現潛…

Redis項目:短信驗證碼登錄

這是黑馬的黑馬點評項目&#xff0c;短信驗證碼的業務。一開始是使用session做的&#xff0c;后來重構&#xff0c;使用redis緩存來完成。 第一層攔截器&#xff1a; public class RefreshTokenInterceptor implements HandlerInterceptor {private StringRedisTemplate stri…

Docker下載,包含Win、Mac

介紹 Docker 是一種開源的容器化平臺&#xff0c;通過操作系統級虛擬化技術實現應用的快速開發、部署和運行。以下從多個維度對 Docker 進行詳細介紹&#xff1a; 一、Docker 的核心概念與功能 容器化技術 Docker 利用 Linux 內核的容器隔離技術&#xff08;如 Cgroups 和 Nam…

使用 ESP8266 和 Android 應用程序實現基于 IOT 的語音控制家庭自動化

使用 ESP8266 實現基于 IOT 的語音控制家庭自動化 歡迎來到另一個令人興奮的項目,我們將使用 Wi-Fi 模塊構建一個語音控制ESP8266家庭自動化系統,您可以在其中通過語音通過 Android 應用程序從世界任何地方控制您的家用電器。是的,您只需使用語音命令即可打開或關閉負載(L…