Ruby Exceptions - 为什么“else”?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Ruby Exceptions - 为什么“else”?相关的知识,希望对你有一定的参考价值。
我试图理解Ruby中的异常,但我有点困惑。我正在使用的教程说,如果发生的异常与rescue语句识别的任何异常都不匹配,您可以使用“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, "
"
如果你能做到这一点,那么我是否需要使用其他?或者我可以像这样在最后使用通用救援?
begin
# -
rescue OneTypeOfException
# -
rescue AnotherTypeOfException
# -
rescue
# Other exceptions
ensure
# Always will be executed
end
else
用于块完成时没有抛出异常。无论块是否成功完成,都会运行ensure
。例:
begin
puts "Hello, world!"
rescue
puts "rescue"
else
puts "else"
ensure
puts "ensure"
end
这将打印Hello, world!
,然后else
,然后ensure
。
这是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
当您可能期望发生某种异常时,会使用开始执行结束块中的else
块。如果你运行了所有预期的异常但仍然没有引发任何异常,那么在你的else块中你可以做任何你需要的事情,因为你知道你的原始代码没有运行。
我可以看到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
感谢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
以上是关于Ruby Exceptions - 为什么“else”?的主要内容,如果未能解决你的问题,请参考以下文章
MAC OS com.mysql.cj.exceptions.CJCommunicationsException:通信链路故障
为啥我得到 MySQLdb._exceptions.OperationalError: (2013, 'Lost connection to MySQL server during query')