其實(shí)選擇 OpenResty
的同學(xué),應(yīng)該都是對(duì)執(zhí)行性能、開發(fā)效率比較在乎的,而對(duì)于代碼風(fēng)格、規(guī)范等這些 小事
不太在意。作為一個(gè)從 Linux C/C++ 轉(zhuǎn)過來的研發(fā),腳本語言的開發(fā)速度,接近 C/C++ 的執(zhí)行速度,在我輕視了代碼規(guī)范后,一個(gè) BUG 的發(fā)生告訴我,沒規(guī)矩不成方圓。
既然我們玩的是 OpenResty
,那么很自然的聯(lián)想到,OpenResty
自身組件代碼風(fēng)格是怎樣的呢?
lua-resty-string 的 string.lua
local ffi = require "ffi"
local ffi_new = ffi.new
local ffi_str = ffi.string
local C = ffi.C
local setmetatable = setmetatable
local error = error
local tonumber = tonumber
local _M = { _VERSION = '0.09' }
ffi.cdef[[
typedef unsigned char u_char;
u_char * ngx_hex_dump(u_char *dst, const u_char *src, size_t len);
intptr_t ngx_atoi(const unsigned char *line, size_t n);
]]
local str_type = ffi.typeof("uint8_t[?]")
function _M.to_hex(s)
local len = #s * 2
local buf = ffi_new(str_type, len)
C.ngx_hex_dump(buf, s, #s)
return ffi_str(buf, len)
end
function _M.atoi(s)
return tonumber(C.ngx_atoi(s, #s))
end
return _M
代碼雖短,但我們可以從中獲取很多信息:
local
限制作用域這里的第 2 條,是有爭議的。當(dāng)你按照這個(gè)方式寫業(yè)務(wù)的時(shí)候,會(huì)有些痛苦。因?yàn)槲覀兛偸前褬?biāo)準(zhǔn) API 命名成自己的別名,不同開發(fā)協(xié)作人員,命名結(jié)果一定不一樣,最后導(dǎo)致同一個(gè)標(biāo)準(zhǔn) API 在不同地方變成不同別名,會(huì)給開發(fā)造成極大困惑。
因?yàn)檫@個(gè)可預(yù)期的麻煩,我們沒有遵循第 2 條標(biāo)準(zhǔn),尤其是具體業(yè)務(wù)上游模塊。但對(duì)于被調(diào)用的次數(shù)比較多基礎(chǔ)模塊,可以使用這個(gè)方式進(jìn)行調(diào)優(yōu)。其實(shí)這里最好最完美的方法,應(yīng)該是 Lua 編譯成 Luac 的時(shí)候,直接做 Lua Byte Code 的調(diào)優(yōu),直接隱藏這個(gè)簡單的處理邏輯。
有關(guān)更多代碼細(xì)節(jié),其實(shí)我覺得主要還是多看寫的漂亮的代碼,一旦看他們看的順眼、形成習(xí)慣,那么就很自然能寫出風(fēng)格一致的代碼。規(guī)定的條條框框死記硬背總是很不爽的,所以多去看看春哥開源的 resty
系列代碼,順手品一品一下不同組件的玩法也別有一番心得。
說說我上面提及的因?yàn)轱L(fēng)格問題造出來的坑吧。
local
function test()
-- do something
end
function test2()
-- do something
end
這是我當(dāng)時(shí)不記得從哪里看到的一個(gè) Lua
風(fēng)格,在被引入項(xiàng)目初期,自我感覺良好??赏蝗粡哪硞€(gè)時(shí)間點(diǎn)開始,新合并進(jìn)來的代碼無法正常工作。查看最后的代碼發(fā)現(xiàn)原來是 test()
函數(shù)作廢,被刪掉,手抖沒有把上面的 local
也刪掉。這個(gè)隱形的 local
就作用到了下一個(gè)函數(shù),最終導(dǎo)致異常。