Ruby Exceptions - 为什么"else"?

Kva*_*ass 50 ruby exception-handling

我试图理解Ruby中的异常,但我有点困惑.我正在使用的教程说,如果发生的异常与rescue语句识别的任何异常都不匹配,您可以使用"else"来捕获它:

begin  
# -  
rescue OneTypeOfException  
# -  
rescue AnotherTypeOfException  
# -  
else  
# Other exceptions
ensure
# Always will be executed
end
Run Code Online (Sandbox Code Playgroud)

但是,我在后面的教程"救援"中也看到了没有指定的异常:

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

如果你能做到这一点,那么我是否需要使用其他?或者我可以像这样在最后使用通用救援?

begin  
# -  
rescue OneTypeOfException  
# -  
rescue AnotherTypeOfException  
# -  
rescue
# Other exceptions
ensure
# Always will be executed
end
Run Code Online (Sandbox Code Playgroud)

Chr*_*ung 93

else没有抛出异常的情况下块完成.ensure无论块是否成功完成,都会运行.例:

begin
  puts "Hello, world!"
rescue
  puts "rescue"
else
  puts "else"
ensure
  puts "ensure"
end
Run Code Online (Sandbox Code Playgroud)

Hello, world!然后else,这将打印出来ensure.

  • @AntarrByrd有一点不同:异常处理程序将在`else`中被禁用(同时仍然在`ensure`之前运行). (6认同)
  • 为什么在开始块中包含else部分? (2认同)

Kel*_*vin 5

elsebegin表达式中的具体用例.假设您正在编写自动化测试,并且您想编写一个返回块引发的错误的方法.但是如果块没有引发错误,您还希望测试失败.你可以这样做:

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

请注意,您无法移动块raise内部begin,因为它会得到rescued.当然,还有其他方法没有使用else,比如检查是否errnil之后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
Run Code Online (Sandbox Code Playgroud)

为什么这不太理想?因为意图是rescuedo_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
Run Code Online (Sandbox Code Playgroud)