以DRY方式将多个错误类传递给ruby的救援条款

apb*_*apb 93 ruby exception rescue

我有一些代码需要在ruby中拯救多种类型的异常:

begin
  a = rand
  if a > 0.5
    raise FooException
  else
    raise BarException
  end
rescue FooException, BarException
  puts "rescued!"
end
Run Code Online (Sandbox Code Playgroud)

我想做的是以某种方式存储我想要在某处救援的异常类型列表,并将这些类型传递给rescue子句:

EXCEPTIONS = [FooException, BarException]
Run Code Online (Sandbox Code Playgroud)

然后:

rescue EXCEPTIONS
Run Code Online (Sandbox Code Playgroud)

这是否可能,并且可能没有一些真正的黑客调用eval?鉴于我在TypeError: class or module required for rescue clause尝试上述内容时所看到的情况,我并不抱希望.

saw*_*awa 187

您可以将数组与splat运算符一起使用*.

EXCEPTIONS = [FooException, BarException]

begin
  a = rand
  if a > 0.5
    raise FooException
  else
    raise BarException
  end
rescue *EXCEPTIONS
  puts "rescued!"
end
Run Code Online (Sandbox Code Playgroud)

如果您要使用上面的数组常量(with EXCEPTIONS),请注意您无法在定义中定义它,如果您在其他类中定义它,则必须使用其命名空间来引用它.实际上,它不一定是常数.


Splat操作员

splat运算符*在其位置"解包"一个数组,以便

rescue *EXCEPTIONS
Run Code Online (Sandbox Code Playgroud)

意思是一样的

rescue FooException, BarException
Run Code Online (Sandbox Code Playgroud)

您也可以在数组文字中使用它

[BazException, *EXCEPTIONS, BangExcepion]
Run Code Online (Sandbox Code Playgroud)

这是一样的

[BazException, FooException, BarException, BangExcepion]
Run Code Online (Sandbox Code Playgroud)

或者在争论的位置

method(BazException, *EXCEPTIONS, BangExcepion)
Run Code Online (Sandbox Code Playgroud)

意思是

method(BazException, FooException, BarException, BangExcepion)
Run Code Online (Sandbox Code Playgroud)

[] 扩展到空虚:

[a, *[], b] # => [a, b]
Run Code Online (Sandbox Code Playgroud)

ruby 1.8和ruby 1.9之间的一个区别是nil.

[a, *nil, b] # => [a, b]       (ruby 1.9)
[a, *nil, b] # => [a, nil, b]  (ruby 1.8)
Run Code Online (Sandbox Code Playgroud)

注意to_a定义的对象,to_a在这种情况下应用:

[a, *{k: :v}, b] # => [a, [:k, :v], b]
Run Code Online (Sandbox Code Playgroud)

对于其他类型的对象,它返回自身.

[1, *2, 3] # => [1, 2, 3]
Run Code Online (Sandbox Code Playgroud)

  • 请注意,如果您要访问的例外情况下,使用此语法:`急救InvalidRequestError,CardError => e`(见http://mikeferrier.com/2012/05/19/rescuing-multiple-exception-types-in-红宝石和结合到本地变量/) (19认同)
  • 这种语法工作得很好:“rescue *EXCEPTIONS => e”,其中“EXCEPTIONS”是异常类名称的数组。 (4认同)
  • 这似乎在ruby 1.8.7中起作用.在这种情况下,在"EXCEPTIONS"前使用'*'字符的术语是什么?想了解更多. (2认同)
  • @Andy它被称为splat.它通常具有将数组分解为逗号分隔对象的效果.当在方法定义的参数接收位置中使用时,它以另一种方式执行:将参数放在一起放入数组中.它在各种场合都很有用.很高兴知道它适用于1.8.7.我相应地编辑了我的答案. (2认同)

Ron*_*ein 9

编辑/更新

我错过了原始问题的全部要点。
虽然接受的答案是有效的,但在我看来,使用建议的技术并不是一个好习惯。人们总是可以拥有一个带有所需(和通用)的包装函数try/rescue


虽然@sawa 给出的答案在技​​术上是正确的,但我认为它滥用了 Ruby 的异常处理机制。

正如Peter Ehrlich的评论所暗示的(通过指向Mike Ferrier 的一篇旧博客文章),Ruby 已经配备了 DRY 异常处理程序机制:

puts 'starting up'
begin
  case rand(3)
  when 0
    ([] + '')
  when 1
    (foo)
  when 2
    (3 / 0)
  end
rescue TypeError, NameError => e
  puts "oops: #{e.message}"
rescue Exception => e
  puts "ouch, #{e}"
end
puts 'done'
Run Code Online (Sandbox Code Playgroud)

通过使用这种技术,我们可以访问异常对象,其中通常包含一些有价值的信息。

  • @Segfault 只有在阅读了你的评论后我才终于理解了OP的问题.. (2认同)