2011-06-08 17 views
40

我想了解Ruby中的異常,但我有點困惑。我使用的教程說,如果發生異常,這不符合任何經搶救聲明中確定的例外,可以用一個「其他」抓住它:Ruby異常 - 爲什麼「其他」?

begin 
# - 
rescue OneTypeOfException 
# - 
rescue AnotherTypeOfException 
# - 
else 
# Other exceptions 
ensure 
# Always will be executed 
end 

不過,我也看到了後面

begin 
    file = open("/unexistant_file") 
    if file 
     puts "File opened successfully" 
    end 
rescue 
    file = STDIN 
end 
print file, "==", STDIN, "\n" 

如果你能做到這一點,那麼我總需要使用別的:在本教程的「救市」未指定的異常被使用?或者我可以像這樣在最後使用通用救援?

begin 
# - 
rescue OneTypeOfException 
# - 
rescue AnotherTypeOfException 
# - 
rescue 
# Other exceptions 
ensure 
# Always will be executed 
end 
+4

有什麼教程,所以我不知道要推薦它? – 2011-06-08 23:42:15

+4

@AndrewGrimm經過一些Google搜索後,我認爲提問者所遵循的教程是http://www.tutorialspoint.com/ruby/ruby_exceptions.htm。Bonus WTF:該教程的作者似乎剽竊了http://rubylearning.com/satishtalim/ruby_exceptions.html中的第一個示例(它已經不正確),但是通過縮小評論的縮進來使其更糟糕。是的,我認爲引導人們遠離它是明智的 - 多麼無能和欺詐的完美結合! – 2015-12-09 19:51:57

回答

76

else適用於塊未完成時拋出異常。無論塊是否成功完成,運行ensure。例如:

begin 
    puts "Hello, world!" 
rescue 
    puts "rescue" 
else 
    puts "else" 
ensure 
    puts "ensure" 
end 

這將打印Hello, world!,然後else,然後ensure

+2

爲什麼在開始塊中包含else部分? – 2015-07-28 16:50:35

+0

@AntarrByrd在Ruby中,'begin'就像其他語言的'try'一樣。這裏'else'意思是,如果在'begin'('try')塊中沒有拋出異常,就這樣做。 – 2015-07-28 16:52:31

+0

但是如果begin塊中的代碼不會引發錯誤。你可以繼續那裏,因爲那是它將運行的唯一情況。 – 2015-07-28 16:54:34

1

在開始救援結束塊中的else塊用於您可能期望發生某種異常的情況。如果你運行了所有預期的異常,但仍然沒有產生任何異常,那麼在你的其他塊中,你可以做任何需要的,現在你知道你的原始代碼沒有錯誤。

4

下面是表達式中else的具體使用案例。假設您正在編寫自動化測試,並且您想編寫一個方法來返回塊引發的錯誤。但是如果塊沒有引發錯誤,你也希望測試失敗。你可以這樣做:

def get_error_from(&block) 
    begin 
    block.call 
    rescue => err 
    err # we want to return this 
    else 
    raise "No error was raised" 
    end 
end 

注意,你不能移動raisebegin塊中,因爲它會得到rescue d。當然,還有其他方法可以不使用else,比如檢查err是否爲nil之後的end,但這並不簡單。

就我個人而言,我很少以這種方式使用else,因爲我認爲這很少需要,但它確實在那些罕見的情況下派上用場。

+0

爲什麼你不能'提高'在'開始救援結束'區塊後沒有發生錯誤?那不是和那個'else'一樣嗎? – Magne 2017-03-06 08:53:04

+0

@Magne唯一可行的方法是如果你還*使用早期的'return',即'return err'而不是'err'。如果您不這樣做,則該方法無法返回該塊的錯誤,因爲您在該方法的末尾有無條件的提升。我通常會盡量避免早期/明確的「返回」(除了guard-clause風格),因爲它更容易遵循;這就是爲什麼'else'語法更具吸引力的原因。 – Kelvin 2017-03-06 17:21:36

+0

啊,我沒有注意到'開始救援結束'是在你想要返回錯誤的方法中。但是,考慮我的問題,如果你不需要返回錯誤(即獨立的「開始救援結束」)。 – Magne 2017-03-07 10:10:20

0

我可以看到else塊的唯一原因是,如果在塊中的代碼沒有引發任何錯誤時,您想在ensure塊之前執行某些操作。

begin 
    puts "Hello" 
rescue 
    puts "Error" 
else 
    puts "Success" 
ensure 
    puts "my old friend" 
    puts "I've come to talk with you again." 
end 
0

感謝else你有時可以合併兩個嵌套begin end塊。
所以(從我當前的代碼簡化的例子),而不是:

begin 
    html = begin 
     NetHTTPUtils.request_data url 
    rescue NetHTTPUtils::Error => e 
     raise unless 503 == e.code 
     sleep 60 
     retry 
    end 
    redo unless html["market"] 
    end 

你寫:

begin 
    html = NetHTTPUtils.request_data url 
    rescue NetHTTPUtils::Error => e 
    raise unless 503 == e.code 
    sleep 60 
    retry 
    else 
    redo unless html["market"] 
    end 
相關問題