bool fn()
{
if(something bad happen)
return false;
..
}
void gn()
{
assert(something == true);
..
}
當我在生產代碼中寫入函數時,我應該用哪種方式選擇 ?斷言與回報錯誤?
bool fn()
{
if(something bad happen)
return false;
..
}
void gn()
{
assert(something == true);
..
}
當我在生產代碼中寫入函數時,我應該用哪種方式選擇 ?斷言與回報錯誤?
Assert
,至少在.NET中,用於測試主要是。其具體用途是把簡潔here:
斷言最適合用來測試一個條件,只有當所有下列條件成立:
* the condition should never be false if the code is correct,
* the condition is not so trivial so as to obviously be always true, and
* the condition is in some sense internal to a body of software.
在生產代碼,我建議第一方法;或者如果預計不會發生「不好的事情」,則可以使用try/catch
;如果這是一種特殊情況。
如果你有一個永遠不應該存在的變量(不管系統的狀態如何),那麼這就是測試用例之外的一個好選擇。
我看到生產代碼中的斷言;通常在design-by-contract style code。我經常在單元測試中看到它們。
恕我直言,assert
是斷言開發人員在調試環境中發生意外(錯誤)的事情。並非所有的斷言都需要至關重要,開發人員必須爲斷言進行真正的失敗。
在發佈模式中,只有在錯誤非常嚴重且沒有任何意義的情況下才需要返回false。
如果代碼正常工作,應該不會發生什麼壞事情時使用斷言。例如:
int div(int a, int b) {
assert(b != 0);
return a/b;
}
這裏,調用代碼有責任確保div()永遠不會被第二個參數調用。如果是這樣,你的代碼處於未知狀態,應該終止。
使用if()...返回發生錯誤時可以處理的情況。例如,打開文件可能會失敗,應該被程序檢測和處理 - 失敗不會使程序進入未知狀態。
簡單的答案是兩者,但第二個更重要。 assert檢查一個設計假設,因此在調用fn()之前,我會有先決條件,例如,一個給定的資源可能是可用的。這個斷言在發佈代碼中通常不會做任何事情,儘管不一定。如果你的函數gn需要某些東西是正確工作是非常重要的,它會使用if語句並返回錯誤代碼或拋出異常。斷言在發佈代碼中通常不會做任何事情,因此在這種情況下您的函數可能會崩潰。
這實際上取決於語言/運行環境更詳細的答案,錯誤的性質。
通常,程序不能從斷言失敗中恢復(即它會崩潰)。這可能是也可能不是你想要的。
如果你的環境支持異常,你也可以使用這些,如果你願意,你可以處理這個錯誤,如果你不處理這個錯誤,它會放棄一個有用的信息。
「返回錯誤」的事情很容易出錯(b/c人忘記檢查返回值),所以我只會在斷言和異常都不可用時才使用它。
即使考慮到使用異常時,「一些事情發生了不好的」你要檢查什麼東西= ...特殊
依賴。在第一種情況下,如果發生的不良事件違反了您的課堂合同,請拋出異常,這對客戶意味着什麼。返回錯誤不會讓任何人知道狀態是不正確的。
使用斷言來記錄和確認程序不變量(你知道它永遠是真的)保持。除了一個簡單的程序之外,您在編寫代碼時會對問題的理解發展,因此舊代碼可能有不同的模型,斷言會幫助您選擇。
對於可以改變的東西(尤其是程序控制之外),您需要能夠報告錯誤(例如,傳入庫函數的入侵參數值,文件不存在),使用平臺/語言首選機制,返回值,...)。
斷言僅用於質量控制目的。刪除它們不得改變程序的行爲(即,程序不得依賴斷言來處理任何事情)。 如果發生不應該發生的事情,則可以使用異常,但可能在惡劣環境下發生 - 例如,網絡連接丟失。當失敗也是一種選擇時,使用返回值來指示成功。
我會使用斷言,只要像合同一樣的東西壞了。這是什麼意思:在數學中,除零除外沒有定義。所以與分工職能的合同被打破了。有關合同的更多信息,請參閱埃菲爾的促進語言。
在某些情況下,我會實現第二個函數,它具有帶缺省值的附加參數並處理異常,如StrinToIntegerDef(string,default),當字符串不轉換爲Integer時返回缺省值。
如果正常執行程序沒有受到威脅,則可以返回false。
如果語言允許,我寧願有意義的異常,至少是表單斷言(條件,消息)。
此外,如果有多種可能性失敗,請返回一些枚舉值而不是false。
使用斷言來強制函數的preconditions(如果函數具有任何意義,必須成立true的條件)。
也是不變式和(在函數結束時)後置條件。 – Richard 2009-05-28 11:27:17
你 「返回false」 也被稱爲GuardClause - 如由Ward Cunningham解釋說:
... [G] uards類似於在斷言 既保護後續 碼從特殊情況。由於他們對 該方法的邏輯做出了有形貢獻,因此他們不會將 與斷言區分開來,因此不能安全地將 作爲優化的一部分省略。 I 在命名這種模式時借用了 EwDijkstra這個術語。
如果您的保護條款具有任何複雜性,那麼使用BouncerPattern進行封裝通常很有幫助。
正如沃德指出的那樣,當代碼可以安全省略時應該使用斷言。如果您的語言中有關鍵字assert
,編譯器通常會從生產代碼中去除斷言。
今天我們認識到,在大多數情況下,在代碼中放置斷言並不是一個好主意。經典的關注點分離。 單獨的斷言代碼和封裝他們在一個單元測試。這消除了必須重新編譯代碼而沒有斷言分發的複雜性(您不會分發您的測試...),並且還爲您提供了一組可以連續運行的測試,以捕獲迴歸和驅動重構。
其他答案已經提到的合同這完全因素這些問題出你的代碼和成圍繞在問題的代碼執行申報的先決條件,後置條件和不變設計。如果您經常這樣做,您可以考慮查看適用於您的語言的Design by Contract框架。
是的,這是我的觀點。我正在使用assert()調用來檢查我的程序中的不變量。當這樣的不變式不被尊重時,由於assert調用會爲我的應用程序生成一個coredump(在調試時),我相信我不會跳過這樣的問題。我希望下一個「負責的開發人員」在應用程序崩潰時注意到某些錯誤......雖然簡單的返回語句最終可能導致文件中存在一些行,但開發人員可以避免。我不是說你可以避免if()測試。我的意思是assert()是一種確保開發者已被強烈通知有問題的方法。 – 2009-05-28 11:16:36