防禦式程式設計是提高軟體質量技術的有益輔助手段。防禦式程式設計的主要思想是:子程式應該不因傳入錯誤資料而被破壞,哪怕是由其他子程式產生的錯誤資料。這種思想是將可能出現的錯誤造成的影響控制在有限的範圍內。以上是引用自百科的一段描述,在實際編碼過程中,我們除了判斷引數是否合法外,還會 assert 非法引數,以達到快速定位出錯位置的目的。
比如我們有乙個 計算兩個 number 之和的乙個函式:
function
add( a, b )
return a + b
end
這個函式在我們傳入正確引數的情況下,可以完成它的功能:
local c = add(3, 5) --返回8
local d = add(100, 200) --返回300
但假如我們只傳入乙個引數:
local e = add(3, nil)
則會報以下錯誤:
attempt to perform arithmetic on a nil value (local 『b』)
所以我們要檢查引數,下面是第二版:
function
add( a, b )
iftype(a)=="number"
andtype(b)=="number"
then
return a + b
endend
這時再傳 nil 進去(或者string/table/etc…),就不會報錯了,函式什麼也不會做,也沒有返回值。
看起來已經可以了,但有時我們還有一些需要,就是希望我們寫的函式,外部在呼叫時,都應該傳入正確的引數,如果填了錯誤的引數,那肯定是呼叫法寫出bug了,這時我們希望能給出醒目的提醒,把問題扼殺在搖籃裡。
這時就需要 assert 了。
下面是加了 assert 後的第三版:
-- 第三版:對錯誤引數零容忍
function
add( a, b )
assert(type(a)=="number"
andtype(b)=="number", "invalid params")
return a + b
end
加 assert 在這種情況下看起來有些過於嚴格了,只是因為這個例子的原因而已,實際上在寫真正的功能時,函式要比這個複雜的多,對錯誤引數的容忍程度也不同,我們先假定我們這個簡單的add
函式對錯誤引數是零容忍的。
這時候,再用非 number 引數呼叫add
,會立即觸發 assert,中止程式的執行,開發者可以馬上看到自己的錯誤用法。
所以我們有乙個較溫和的版本,只記錄出錯日誌,而不 assert ,如下:
-- 第四版:唔,偶爾犯點錯可以接受,只記過不開除
function
add( a, b )
iftype(a)~="number"
ortype(b)~="number"
then
print("invalid param", tostring(a), tostring(b))
return
endreturn a + b
end
好了,以上第三版和第四版就是我們的所有需求了,只不過每次都要寫這麼多**「防禦」,也太麻煩了,有沒有自動化的解決方案?
當然有了,會偷懶的程式設計師才是好的程式設計師,let』s go!
-- 防禦式程式設計 輔助函式
-- 第三版:對引數零容忍的輔助函式
function
check
( condition )
ifnot condition then
log.e("check failed!!", tostring(condition))
assert(false, "check failed!!")
endend-- 第四版:只記 log 不 assert
function
ok( condition )
ifnot condition then
log.e("if_ok!!")
return
false
else
return
true
endend
-- 同樣是第四版,只記 log 的,但跟 ok 用法相反
function
not( condition )
ifnot condition then
log.e("if_not!!")
return
true
else
return
false
endend
-- 注:上述函式中的 log.e,請換為自己專案中記錄錯誤日誌的函式。
好了,讓我們用上面的輔助函式重寫我們的add
函式:
-- 第三版:對錯誤引數零容忍
function
add( a, b )
-- 一旦條件為假,就會 assert,並記錄錯誤日誌(含呼叫棧資訊,方便查線上問題)
check(type(a)=="number"
andtype(b)=="number")
return a + b
end-- 第四版:只記 log 不 assert
function
add( a, b )
-- 一但「不ok」,就會記錄錯誤日誌,但不會assert
-- ok條件返回 false, 所以 if 內的邏輯不會執行,跟直接用 if 判斷效果一樣
if ok(type(a)=="number"
andtype(b)=="number") then
return a + b
endend-- 第四版也可以這麼寫
-- 但這樣寫極不自然,看著非常費勁,not 也不是這麼用的
-- 關於ok和not,各自有各自的應用場景,如果現在不理解可以只用check和ok,這兩個用多了以後
-- 就知道not是幹嘛的了 ;-)
function
add( a, b )
if not(type(a)~="number"
ortype(b)~="number") then
return
endreturn a + b
end
check
可以認為就是乙個會打錯誤日誌的assert
。
ok
和not
都是在判斷的條件為 false 時,記錄下錯誤日誌,但並不會觸發 assert。
在日常編碼過程中,對於一些關鍵的、不希望為假的、一旦為假必為bug的條件,可以使用 ok 和 not 判斷,但不要濫用,普通的條件(true/false都為正常情況的)不建議使用。
end
防禦式程式設計
防禦式程式設計 防禦式程式設計的主要思想是 子程式應該不因傳入錯誤資料而被破壞,哪怕是由其他子程式產生的錯誤資料。更一般地說,其核心思想是要承認程式都會有問題,都需要修改,聰明的程式設計師應該根據這一點來程式設計序。我們心裡應該自始至終考慮各種各樣的錯誤處理機制 在區域性處理錯誤 使用錯誤碼來傳遞錯...
防禦式程式設計
場景 交易終端支援市中核算,必須需要處理當日的委託和成交資料,現系統的委託和成交在本地快取和遠端快取中各有乙份。思路 核算優先使用本地快取,本地快取不存在那麼就 防禦式 取遠端快取。實現package demo.design.defensive 專案 demo design defensive 場景...
防禦式程式設計
檢查所有 於外部的資料的值,檢查輸入值的合法性,與我們在註冊資訊是的正規表示式類似。斷言一般用於開發和維護階段,斷言為真,程式正常執行,斷言為假,程式出錯。斷言只在開發階段被編譯到目標 中,在生產產品中不編譯進去。使用斷言的指導意見 斷言是用來檢查永遠不該發生的情況,比如我們對於年齡的檢查,年齡不能...