我正在尝试理解Ruby中的异常,但我有点困惑。我正在使用的教程说,如果发生的异常与救援语句中指出的任何异常都不匹配,您可以使用“else”来捕获它:
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
答案 0 :(得分:89)
else
用于块完成时没有抛出异常。无论块是否成功完成,都会运行ensure
。例如:
begin
puts "Hello, world!"
rescue
puts "rescue"
else
puts "else"
ensure
puts "ensure"
end
这将打印Hello, world!
,然后是else
,然后是ensure
。
答案 1 :(得分:5)
这是else
表达式中begin
的具体用例。假设您正在编写自动化测试,并且您想编写一个返回块引发的错误的方法。但是如果块没有引发错误,您还希望测试失败。你可以这样做:
def get_error_from(&block)
begin
block.call
rescue => err
err # we want to return this
else
raise "No error was raised"
end
end
请注意,您无法移动raise
区域内的begin
,因为它会获得rescue
d。当然,还有其他方法可以不使用else
,例如在err
之后检查nil
是否end
,但这并不简洁。
就个人而言,我很少以这种方式使用else
,因为我认为它很少需要,但在极少数情况下它会派上用场。
修改强>
另一个用例发生在我身上。这是一个典型的begin
/ rescue
:
begin
do_something_that_may_raise_argument_error
do_something_else_when_the_previous_line_doesnt_raise
rescue ArgumentError => e
handle_the_error
end
为什么这不太理想?因为当rescue
提升do_something_that_may_raise_argument_error
时,意图是ArgumentError
,而当do_something_else_when_the_previous_line_doesnt_raise
提出时,不是。
通常最好使用begin
/ rescue
将您想要保护的最小代码包装在raise
之内,否则:
raise
rescue
的意图难以破译。有人(包括你未来的自己)可能会阅读代码并想知道"我想保护哪个表达?它看起来就像表达ABC ......但也许表达DEF也是????作者的意图是什么?!"重构变得更加困难。通过这个简单的改变可以避免这些问题:
begin
do_something_that_may_raise_argument_error
rescue ArgumentError => e
handle_the_error
else
do_something_else_when_the_previous_line_doesnt_raise
end
答案 2 :(得分:1)
当您可能期望发生某种异常时,将使用begin rescue end block中的else
块。如果您运行了所有预期的异常但仍然没有引发任何异常,那么在您的else块中,您可以做任何您需要的事情,因为您知道原始代码没有运行。
答案 3 :(得分:0)
我可以看到else
块的唯一原因是,当ensure
块中的代码没有引发任何错误时,如果要在begin
块之前执行某些操作。
begin
puts "Hello"
rescue
puts "Error"
else
puts "Success"
ensure
puts "my old friend"
puts "I've come to talk with you again."
end
答案 4 :(得分: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