115

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

begin
  a = rand
  if a > 0.5
    raise FooException
  else
    raise BarException
  end
rescue FooException, BarException
  puts "rescued!"
end

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

EXCEPTIONS = [FooException, BarException]

进而:

rescue EXCEPTIONS

这甚至可能吗,如果没有一些真正的hack-y调用是否有可能eval?鉴于我在TypeError: class or module required for rescue clause尝试上述操作时看到的,我不抱希望。

4

3 回答 3

221

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

EXCEPTIONS = [FooException, BarException]

begin
  a = rand
  if a > 0.5
    raise FooException
  else
    raise BarException
  end
rescue *EXCEPTIONS
  puts "rescued!"
end

如果您要使用上述数组的常量(使用EXCEPTIONS),请注意您不能在定义中定义它,并且如果您在其他类中定义它,则必须使用其命名空间来引用它。实际上,它不必是一个常数。


喷溅操作员

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

rescue *EXCEPTIONS

意思是一样的

rescue FooException, BarException

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

[BazException, *EXCEPTIONS, BangExcepion]

这与

[BazException, FooException, BarException, BangExcepion]

或在争论的位置

method(BazException, *EXCEPTIONS, BangExcepion)

意思是

method(BazException, FooException, BarException, BangExcepion)

[]扩展为空:

[a, *[], b] # => [a, b]

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

[a, *nil, b] # => [a, b]       (ruby 1.9)
[a, *nil, b] # => [a, nil, b]  (ruby 1.8)

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

[a, *{k: :v}, b] # => [a, [:k, :v], b]

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

[1, *2, 3] # => [1, 2, 3]
于 2011-04-25T20:19:26.200 回答
12

编辑/更新

我错过了原始问题的全部要点。
虽然公认的答案是有效的,但在我看来,使用建议的技术并不是一个好习惯。人们总是可以有一个带有期望(和通用)的包装函数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'

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

于 2019-11-05T13:54:41.953 回答
2

我刚刚遇到这个问题并找到了替代解决方案。如果您的FooExceptionBarException都将是自定义异常类,特别是如果它们都与主题相关,您可以构建继承层次结构,使它们都从同一个父类继承,然后只拯救父类。

例如,我有三个例外:FileNamesMissingErrorInputFileMissingErrorOutputDirectoryError我想用一个语句来拯救。我创建了另一个异常类FileLoadError,然后将上述三个异常设置为继承自它。那时我才救了FileLoadError

像这样:

class FileLoadError < StandardError
end

class FileNamesMissingError < FileLoadError
end

class InputFileMissingError < FileLoadError
end

class OutputDirectoryError < FileLoadError
end

[FileNamesMissingError,
 InputFileMissingError,
 OutputDirectoryError].each do |error| 
   begin  
     raise error
   rescue FileLoadError => e
     puts "Rescuing #{e.class}."
   end 
end
于 2015-06-15T00:13:49.857 回答