【问题标题】:How to raise multiple exceptions in ruby如何在 ruby​​ 中引发多个异常
【发布时间】:2018-12-21 11:40:15
【问题描述】:

在 ruby​​ 中,您可以像这样重新定义多个异常:

begin
   ...
rescue Exception1, Exception2
  ...
rescue Exception1
  ...
rescue Exception2
  ...
end

但我不知道如何引发多个异常:

1] pry(main)> ? raise

From: eval.c (C Method):
Owner: Kernel
Visibility: private
Signature: raise(*arg1)
Number of lines: 13

With no arguments, raises the exception in $! or raises
a RuntimeError if $! is nil.
With a single String argument, raises a
RuntimeError with the string as a message. Otherwise,
the first parameter should be the name of an Exception
class (or an object that returns an Exception object when sent
an exception message). The optional second parameter sets the
message associated with the exception, and the third parameter is an
array of callback information. Exceptions are caught by the
rescue clause of begin...end blocks.

   raise "Failed to create socket"
   raise ArgumentError, "No parameters", caller

或者我无法在raise doc中找到这个

这样做的目的是我有一个 API 调用,这个调用试图在 API 中创建一个对象。 然后 APi 可以从 Activerecord Validators 返回对象中的所有问题,所以我可以得到这样的想法,例如:

422 "The Item is not even","The Item 需要大于 100" 第422章 200 OK “项目已创建” 500“我是个发球台

我们的想法是捕获这个并引发这样的异常

Begin
API CALL
rescue ItemnotEven,ItemnotBigger
do something 
retry if 
rescue ItemnotEven
retry if
rescue Connection error
Log cannot connect
end

【问题讨论】:

  • 引发多个异常的目的是什么?
  • 通过引发多个异常甚至不清楚您的意思。当您说可以挽救多个异常时,它们不会同时保存;你可以一次养一只。
  • 目的是我可以得到一个对象构造的多次失败,所以每次失败我都会抛出一个异常
  • 引发多个异常甚至没有意义,而且我个人不知道有任何语言可以实现这样的事情。有诸如内部异常之类的事情,其中​​一个导致另一个,但没有引发它们....

标签: ruby validation exception exception-handling


【解决方案1】:

不应将异常用于验证。基本上,您通常不应该遍历堆栈进行验证。

你基本上在做的是:

X 是顶级的,可以处理所有事情。 X 调用 Y。Y 调用 Z。Z 执行验证并在此之后执行某些操作,如果验证失败则引发异常。

你应该做的是:

X 调用 Y。Y 调用 V 和 X。V 执行验证并根据事物是否有效返回结果。如果 V 说事情是无效的,Y 就不能打电话给 X。 Y 将无效或成功的结果传播给 X。X 在有效性上执行它对 if/else 所做的事情,而不是 rescue。


但是假设你真的很想这样做。你应该改用throw/catch:

def validate_date(date)
  errors = []

  errors << 'Improper format' unless date.match?(/^\d{2}-\d{2}-\d{4}$/)
  errors << 'Invalid day' unless date.match?(/^[0-3]\d/)
  errors << 'Invalid month' unless date.match?(/-[12]\d-/)
  errors << 'Invalid year' unless date.match?(/[12][90]\d{2}$/)

  throw(:validation, errors) unless errors.empty?
end

def invoke_validation_and_do_stuff(date)
  validate_date(date)
  puts "I won't be called unless validation is successful for #{date}"
end

def meaningless_nesting(date)
  invoke_validation_and_do_stuff(date)
end

def more_meaningless_nesting(date)
  meaningless_nesting(date)
end

def top_level(date)
  validation_errors = catch(:validation) do
    more_meaningless_nesting(date)
    nil
  end

  if validation_errors
    puts validation_errors
  else
    puts 'Execution successful without errors'
  end
end


top_level '20-10-2012'
  # I won't be called unless validation is successful for 20-10-2012
  # Execution successful without errors

top_level '55-50-2012'
  # Invalid day
  # Invalid month

【讨论】:

  • 感谢您的澄清,但如果我想在更正错误后重试会发生什么
  • @anquegi in top_level 您可以查看validation_errors 是否包含您知道如何“修复”的错误。如果是这样,请执行一些执行“修复”的操作。然后再次调用top_level(又名递归)。
  • 感谢最后的澄清,这真的是一个很好的答案
  • @anquegi 很高兴它有帮助。
【解决方案2】:

我不认为你可以引发多个异常,它会引发它发现的第一个异常,如果存在多个异常或取决于你引发的异常类型和救援类型,它将被最里面的救援语句捕获

【讨论】:

    【解决方案3】:

    在我知道的任何语言中都不存在这样的概念。 您可以连续引发单个异常,但不能一次引发多个异常,即使在多个线程上“同时”引发,它仍然是在不同的控制流上引发的单个异常。

    当引发异常时,控制流会转到该异常。你有两个选择:做点什么,或者崩溃。没有第三个选项,也没有单独的控制流弹出并继续,直到相应地处理此异常。

    如果您希望看到评论中所述的多次失败,那么您仍将一次只进行一次,就像它们将被提出的方式一样。引发异常,您检查、记录、执行任何操作、抑制它,然后查看下一个是否因其他原因引发异常。

    如果您要问如何引发多个未处理的异常,那真的没有意义。这类似于询问如何同时在两个地方。

    【讨论】:

      猜你喜欢
      • 2018-12-24
      • 2019-08-04
      • 2013-10-19
      • 1970-01-01
      • 2010-09-21
      • 2012-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多