ruby:在异常

时间:2017-08-24 15:21:04

标签: ruby-on-rails ruby

我觉得有点奇怪,因为有很多问题有点像这样,但不够接近,或者没有答案。

[编辑:我正在改写这个问题以使其更清晰]

我有一个循环,它做了很多事情,并且正在玩它以查看各种选项是否有助于使事情更具可读性,更清晰。最后,我搞砸了一些东西,然后抛出了异常,这就是救援。到现在为止还挺好。但是,我无法找到任何方法让ruby在循环的同一次迭代中继续使用以下语句 - 异常总是会产生以下语句并继续进行下一次迭代 - 默认行为。重做或重试将毫无意义,导致无限循环,再次遇到相同的错误和异常等,

我有什么方法可以强迫ruby以某种方式处理错误,然后继续它离开的地方?

这是一个样本,从我不知道在哪里偷来并改编。

3.times do |i|
  begin
    # first bunch of stuff to do
    # second bunch of stuff to do
    # third bunch of stuff to do
    # fourth bunch of stuff to do
  rescue => e
    p e
  end
end

基本上,在这个例子中,我希望在继续循环的下一次迭代之前执行所有四个东西,即使其中一个应该导致错误。我不是要处理错误,允许我看到异常结果等,但有效地忽略它并继续做其他所有东西。

有什么想法吗?这可能是我以前从未见过的非常明显的事情。

2 个答案:

答案 0 :(得分:2)

begin块(包括来自def的隐式块)以第一个异常结束。如果你想在不管成功/失败的情况下单独做某事,那就把它放在街区之外。

3.times do |i|
  begin
    raise "Raised from iteration #{i}"
  rescue => e
    p e
  end
  puts "I'm after the exception"
end

如果您想在returnbreak等之后执行某些操作,请使用ensure块。

5.times do |i|
  begin
    break if i == 3
    raise "Raised from iteration #{i}"
  rescue => e
    p e
  ensure
    puts "I always run #{i}"
  end
end

哪个输出:

#<RuntimeError: Raised from iteration 0>
I always run 0
#<RuntimeError: Raised from iteration 1>
I always run 1
#<RuntimeError: Raised from iteration 2>
I always run 2
I always run 3

如果你真的想忽略并继续许多可能抛出的语句,它们每个都需要一个单独的rescue块。您可以使用另一个包装器方法执行此操作。但是要非常小心,忽略的例外实际上并不重要,因为继续是安全的。

设计上的异常是为了中止以下操作并尽量避免留下不一致和未知的程序状态。

def suppress
  yield
rescue => e
  puts "Supressing #{e}"
end
5.times do |i|
  suppress { raise "I throw sometimes #{i}" if i <= 3 }
  suppress { raise "I throw sometimes too #{i}" if i > 2 }
  puts "After possible exceptions #{i}"
end

输出:

Supressing I throw sometimes 0
After possible exceptions 0
Supressing I throw sometimes 1
After possible exceptions 1
Supressing I throw sometimes 2
After possible exceptions 2
Supressing I throw sometimes 3
Supressing I throw sometimes too 3
After possible exceptions 3
Supressing I throw sometimes too 4
After possible exceptions 4

答案 1 :(得分:2)

您正在使用begin-end子句定义rescue块。如果块引发任何异常并且存在匹配的rescue子句,则块将停止执行并执行rescue子句。如果没有匹配的救援块,错误将会冒出来(希望由另一个块处理,否则它将被处理,你的脚本将停止!)如果有一个ensure子句,那么它也会被运行即使有例外。

那么我们离开了哪里?如果你想要防止个别步骤的失败并继续,无论如何,每一步都需要自己的阻止:

3.times do |i|
  begin
    first_thing
  rescue => e
    puts "The first thing blew up! #{e.inspect}"
    puts "I'll carry on anyway ¯\\_(ツ)_/¯"
  end

  begin
    second_thing
    third_thing
  rescue => e
    puts "Either the second or third thing blew up... #{e.inspect}"
    puts "Straight on to the fourth thing!"
  end

  begin
    fourth_thing
  rescue => e
    puts "Fourth thing blew up! #{e.inspect}"
  end
end

有一个像这样的块有点不寻常,如果出现问题就应该继续执行 - 这通常是让下一个步骤出错的好方法!您可能需要确保在每个点上仍然具有数据完整性,并且后面的步骤不依赖于在先前步骤中可能未发生的事情。