2010-03-07 48 views
4

可能重複:
How can I cleanly handle error checking in Perl?
What’s broken about exceptions in Perl?如果在Perl代碼中出現錯誤,最佳做法是什麼?

我看到代碼的工作原理是這樣的:

do_something($param) || warn "something went wrong\n"; 

,我也看到了這樣的代碼:

eval { 
    do_something_else($param); 
}; 
if([email protected]) { 
    warn "something went wrong\n"; 
} 

我應該在所有子程序中使用eval/die嗎?我應該根據從子例程返回的東西編寫我的所有代碼嗎?是不是eval'代碼(一遍又一遍)會減慢我的速度?

+2

假裝別人寫了嗎? ;) – 2010-03-07 11:28:07

+0

是啊:)。有點難以說出作者:Geo。 :) – Geo 2010-03-07 11:29:29

+0

有關Perl中異常的廣泛討論,請參閱http://stackoverflow.com/questions/2165161/whats-broken-about-exceptions-in-perl – Ether 2010-03-07 16:53:27

回答

2

第一個版本非常「完美」,而且非常直觀易懂。這個習慣用語的唯一缺點是它只能在短時間內閱讀。如果錯誤處理需要更多邏輯,請使用第二個版本。

13

Block eval不是字符串eval,所以不,它不慢。使用它是絕對推薦的。

有一些惱人的細微之處是它的工作原理雖然這樣(的事實[email protected]是一個全局變量大多是討厭的副作用),所以請考慮使用Try::Tiny,而不是記住所有你需要使用的小動作eval防守。

6
do_something($param) || warn "something went wrong\n"; 

在這種情況下,do_something預計,如果出現錯誤返回錯誤代碼。要麼它不能死亡,要麼就是這樣,這是一種非常不尋常的情況。

eval { 
    do_something_else($param); 
}; 
if([email protected]) { 
    warn "something went wrong\n"; 
} 

這裏,假設是由do_something_else通信出亂子的唯一機制是通過拋出異常。

如果do_something_else在真正例外的情況下拋出異常並在其他情況下返回錯誤值,您還應該檢查其返回值。

使用的eval塊形式不會導致在運行時編譯外,所以沒有嚴重的性能缺點:

在第二種形式,塊內的代碼被解析只有一次 - 在同時圍繞eval本身的代碼被解析 - 並在當前Perl程序的上下文中執行。此表單通常用於比第一個更有效地捕獲異常(請參見下文),同時還提供了在編譯時檢查BLOCK內的代碼的好處。

5

你的兩個例子完全不同的事情。第一個檢查一個錯誤的返回值,並採取一些行動作爲迴應。第二個檢查被調用代碼的實際死亡。

你必須自己決定哪個動作是在每種情況下適當的。我建議在大多數情況下簡單地返回false。你只應明確die荷蘭國際集團,如果你遇到了錯誤非常嚴重,你不能繼續(或者沒有點在繼續,但即使如此,你仍然可以返回false)。

eval {}中包裝塊與在eval ""中包裝任意代碼不同。在前一種情況下,代碼在編譯時仍然被解析,並且不會產生額外的開銷。你會簡單地趕上代碼的任何死亡(但你不會有任何指示,以什麼地方出了錯或多遠,你在你的代碼了,但是,被在[email protected]留給你的價值)。在後一種情況下,代碼被視爲由Perl解釋一個簡單的字符串,直到它實際上是等價的,所以有一定的成本這裏的解釋器中調用(和你失去所有的編譯時代碼的檢查)。

順便說一下,您稱爲eval並檢查值爲[email protected]的方式不是推薦形式;有關Perl中異常陷阱和技術的廣泛討論,請參閱this discussion

+0

當我返回false時,我應該怎麼去提供錯誤信息? – Geo 2010-03-07 19:44:01

+0

@Geo:你可以用'warn()'向stderr輸出一個字符串,或者使用日誌工具(如Log :: Log4perl)記錄一條消息。 – Ether 2010-03-07 20:17:35

2

沒有人真正解決這個「最佳實踐」的一部分,所以我會在跳。

是的,你應該絕對拋出一個異常,在代碼中出問題的時候,你應該做的它儘可能早(所以你限制了需要調試的代碼來找出造成它的原因)。 ,做這樣的東西回報undef來表示失敗

代碼不是特別可靠,僅僅是因爲人們往往會使用它沒有檢查民主基金返回值 - 這意味着他們假設一個變量一些有意義的,它實際上可能不是。這導致了複雜的,難以調試的問題,甚至在之前的代碼中出現意外的問題。

更堅實的方法是編寫代碼,以便它死,如果出現錯誤,然後只有當你需要從失敗收回,換到它的任何電話中eval{ .. }(或更好,try { .. } catch { .. }如上所述,從Try::Tiny)。在大多數情況下,調用代碼可以恢復的內容沒有任何意義,所以在常見情況下調用代碼仍然很簡單,並且您可以假設您將獲得有用的值。如果出現問題,那麼你會從代碼失敗的實際部分得到一條錯誤消息,而不是默默得到一個undef。如果你調用代碼可以做一些恢復失敗,那麼就可以安排捕獲異常,做任何需要的地方。

東西是值得一讀的是Exception classes,這是發送額外的信息,調用代碼,以及允許它挑就是了哪些異常捕獲和它不能處理結構化的方式。你可能不會想在你的代碼在任何地方使用他們,但他們是一個有用的技術,當你有一些複雜的,可以在同樣複雜的方式失敗,並要安排的失敗是可以恢復的。

6

模塊warn是很煩人的。無論成功還是失敗。不要將任何東西打印到終端上,然後繼續運行;我的程序無法根據您打印的某條消息採取措施。如果程序可以繼續運行,只有在您明確告知它沒有問題的情況下才打印消息。如果程序無法繼續運行,die。這就是它的目的。

出現問題時總是拋出異常。如果你能解決這個問題,請修復它。如果你不能解決問題,不要嘗試;只是拋出異常並讓調用者處理它。 (如果你不能處理你打電話的異常,請不要。)

基本上,很多程序都是bug的原因是因爲他們試圖修復它們無法解決的錯誤。在出現問題的第一個信號時,乾淨地死去的程序很容易調試和修復。一旦遇到困惑,程序就會繼續運行,只會破壞數據並惹惱所有人。所以不要這樣做。儘快死亡。

相關問題