代码之家  ›  专栏  ›  技术社区  ›  anquegi

如何在ruby中引发多个异常

  •  2
  • anquegi  · 技术社区  · 6 年前

    在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验证器返回对象中的所有问题,这样我就可以像这样思考:

    422“项目不均匀”,“项目也需要大于100” 422“物品不均匀” 200确定“项目已创建” 500“我是个球罐

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

    Begin
    API CALL
    rescue ItemnotEven,ItemnotBigger
    do something 
    retry if 
    rescue ItemnotEven
    retry if
    rescue Connection error
    Log cannot connect
    end
    
    3 回复  |  直到 6 年前
        1
  •  5
  •   ndnenkov    6 年前

    异常不应用于验证。基本上,一般情况下不应该遍历堆栈进行验证。

    从根本上说,你所做的是:

    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
    
        2
  •  1
  •   Subash    6 年前

    我认为您不能举多个异常,它会引发它发现的第一个异常,如果存在多个异常,它将被最内层的救援语句捕获,或者取决于您所引发的异常类型和救援类型。

        3
  •  1
  •   ForeverZer0    6 年前

    在我意识到的任何语言中都没有这样的概念。 可以连续引发单个异常,但不能同时引发多个异常,即使在多个线程上“同时”引发,也仍然是在不同的控制流上引发的单个异常。

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

    如果你想看到你在评论中所说的多次失败,那么你仍然会一次一次地失败,就像他们是如何被提出的一样。异常被引发,您可以检查、记录、执行任何操作、抑制它,并查看下一个异常是否因其他原因被引发。

    如果您询问如何引发多个未处理的异常,那么这真的没有意义。这就好比问如何同时在两个地方。