2017-08-24 111 views
2

我覺得有點奇怪,因爲有一些問題有點像這樣,但是不夠接近或者沒有答案。ruby​​:在異常後繼續進行同樣的循環迭代

[編輯:我改寫的問題,以使其更清晰]

我有一個循環,做了一些事情,並用它玩,看看各種選項將努力使事情更易讀,清潔器。最後,我搞砸了一些東西,它被拋出並且異常,這是在救援時遇到的。到現在爲止還挺好。然而,我不能找到任何方法讓ruby在循環的同一次迭代中繼續使用以下語句 - 異常總是會產生以下語句,並轉移到下一次迭代 - 默認行爲。重做或重試將是毫無意義的,並導致無限循環,再次發生同樣的錯誤和異常,等等,

我有什麼辦法強制ruby以某種方式處理錯誤,然後只是繼續它離開的地方?

這裏是一個樣本,從我不知道在哪裏偷來,並適應。

3.times do |i| 
    begin 
    # first bunch of stuff to do 
    # second bunch of stuff to do 
    # third bunch of stuff to do 
    # fourth bunch of stuff to do 
    rescue => e 
    p e 
    end 
end 

基本上,在這個例子中,我想要的東西串的所有四個對移動到循環的下一次迭代中,即使其中一個應該引起錯誤之前執行。我不是要處理這個錯誤,讓我看到異常結果等等,但是有效地忽略它並繼續做其他所有事情。

任何想法?這可能是我以前從未見過的真正明顯的事情。

+0

無論是否發生異常,是否應該執行'puts'? – Stefan

+0

是的。這模擬了我正在搞亂的主程序中的字符串操作等等。 – MrBungleBear

+0

如果您使用故意的流量控制異常,這可能是一個錯誤。爲什麼不只是一個'if'? – tadman

回答

2

你定義一個與rescue子句begin-end塊。如果任何異常是由塊引發的並且有一個匹配的救援條款,則該塊將停止執行,並執行救援條款。如果沒有匹配的救援塊,這個錯誤就會冒泡(並且希望能夠被另一個塊處理,否則它將被處理並且你的腳本將停止!)如果存在子句,那麼即使存在例外。

那麼,這是否離開我們?如果要抵禦的各個步驟失敗,繼續不分,每一步都需要自己的塊:

3.times do |i| 
    begin 
    first_thing 
    rescue => e 
    puts "The first thing blew up! #{e.inspect}" 
    puts "I'll carry on anyway ¯\\_(ツ)_/¯" 
    end 

    begin 
    second_thing 
    third_thing 
    rescue => e 
    puts "Either the second or third thing blew up... #{e.inspect}" 
    puts "Straight on to the fourth thing!" 
    end 

    begin 
    fourth_thing 
    rescue => e 
    puts "Fourth thing blew up! #{e.inspect}" 
    end 
end 

這有點不尋常的一個塊這樣應該對執行進行,如果出現錯誤 - 這通常是讓下一個步驟之一出錯的好方法!您可能需要確保您在每個時間點仍然具有數據完整性,並且後面的步驟不依賴於在先前步驟中可能未發生的事情。

+0

謝謝所有 - 我想我有我的答案。沒有什麼內置的,真的,做錯誤處理然後繼續。如果我想要做到這一點,單獨的區塊就可以走了。這有點笨重,但你很少能夠獲得生活中的一切!這裏的基礎是從一個文件中讀取一行,在檢查網絡已經存在並且可以打開並且我們實際上已經打開一行,然後對它執行大量獨立的事情,所以我很舒服直到這種錯誤和情況,這讓我在浪費時間在非工作解決方案上花了一整天的時間後走上了這條路。 :) – MrBungleBear

2

A begin塊(包括來自說明def的隱含塊)以第一個異常結束。無論成功/失敗,如果你想單獨做某件事,那就把它放在塊之外。

3.times do |i| 
    begin 
    raise "Raised from iteration #{i}" 
    rescue => e 
    p e 
    end 
    puts "I'm after the exception" 
end 

如果你想即使經過returnbreak做一些事情,等於是使用ensure塊。

5.times do |i| 
    begin 
    break if i == 3 
    raise "Raised from iteration #{i}" 
    rescue => e 
    p e 
    ensure 
    puts "I always run #{i}" 
    end 
end 

,輸出:

#<RuntimeError: Raised from iteration 0> 
I always run 0 
#<RuntimeError: Raised from iteration 1> 
I always run 1 
#<RuntimeError: Raised from iteration 2> 
I always run 2 
I always run 3 

如果你真的想忽略和可能引發許多語句繼續,他們每個人都需要一個單獨的rescue塊。你可以用另一個包裝方法來做到這一點。然而,要非常小心,被忽視的例外並不重要,而是繼續是安全的。

設計異常,意味着放棄以下操作,並儘量避免使不一致和未知的程序狀態。

def suppress 
    yield 
rescue => e 
    puts "Supressing #{e}" 
end 
5.times do |i| 
    suppress { raise "I throw sometimes #{i}" if i <= 3 } 
    suppress { raise "I throw sometimes too #{i}" if i > 2 } 
    puts "After possible exceptions #{i}" 
end 

輸出:

Supressing I throw sometimes 0 
After possible exceptions 0 
Supressing I throw sometimes 1 
After possible exceptions 1 
Supressing I throw sometimes 2 
After possible exceptions 2 
Supressing I throw sometimes 3 
Supressing I throw sometimes too 3 
After possible exceptions 3 
Supressing I throw sometimes too 4 
After possible exceptions 4 
+0

感謝Fire Lancer - 但是,如果您知道某段代碼可能會通過併發生異常,那麼該方法就有效。如果你不知道,或者不知道哪一塊,你想拯救環繞所有的代碼,所以你不一定這樣做。想象一下,提高實際上是一個負載的東西,可能在某種程度上,給定一些條件,拋出一個異常。 – MrBungleBear

+0

一般來說,它不安全,在發生異常之後繼續「下一個語句」,並且會很困難,如果你真的想,你需要以某種方式明確地包裝它們,或者單獨展開開始塊或者一些包裝器方法 –

+0

你不想寫YOLO代碼,通過異常來推土機,並繼續前進。 – tadman