【问题标题】:How to use custom error messages如何使用自定义错误消息
【发布时间】:2015-09-22 00:40:04
【问题描述】:

当我使用非数字输入测试我的代码时,Ruby 会引发一条默认消息。相反,每当引发异常时,我希望我的自定义消息使用默认的backtrace.inspect 打印。我期望:

"oops... That was not a number"

被提升而不是:

invalid value for Float(): "h\n" (ArgumentError)

受以下文档的启发,我编写了以下代码: stackoverflow, rubylearning, github.

class MyCustomError < StandardError
  def message
    "oops... That was not a number"
  end
end

def print_a_number
  begin
    puts "chose a number"
    number = Float(gets)
    raise MyCustomError unless number.is_a? Numeric
    puts "The number you chose is #{number}"
  rescue MyCustomError => err
    puts err.message  
    puts err.backtrace.inspect  
  end  
end

以下代码的行为确实符合我的预期;我不明白为什么下面的代码会打印我的默认消息,而上面的代码却没有:

class MyCustomError < StandardError
  def message
    "The file you want to open does not exist"
  end
end

def open_a_file

  begin
    puts "What file do you want to open?"
    file2open = gets.chomp

    raise MyCustomError unless File.file?(file2open)

    File.open(file2open, 'r') { |x|  
            while line = x.gets 
                puts line
            end
        }

  rescue MyCustomError => err
    puts err.message
    puts err.backtrace.inspect

  end
end

【问题讨论】:

  • 你有什么问题?

标签: ruby exception-handling


【解决方案1】:

只需像这样修改你的脚本。

class MyCustomError < StandardError
  def message
    "oops... That was not a number"
  end
end

def print_a_number
  begin
    puts "chose a number"
    number = Float(gets) rescue false
    raise MyCustomError unless number.is_a? Numeric
    puts "The number you chose is #{number}"
  rescue MyCustomError => err
    puts err.message
    puts err.backtrace.inspect
  end
end

【讨论】:

  • 我了解内联救援代码的使用:它将救援 Float(gets) 引发的错误并返回 false(或其他任何内容)。因此,如果没有 begin-rescue-end Ruby,它会返回“您选择的数字是错误的”或“您选择的数字是错误的输入”,如果我们使用救援“错误输入”而不是救援错误。使用 begin-rescue-end 构造,这不会发生,所以我们在内联救援之后放置的内容似乎是任意的,因为任何错误都会被 MyCustomError 救援。那么在这种情况下,内联救援是如何工作的呢?
  • 我不明白你想说什么。 “number = Float(gets)rescue false”中的rescue 关键字可以保护Float 方法的任何可能的解析错误,因为它是begin 关键字之后唯一可能引发错误的语句。这是一个隐式救援,使用救援“错误输入”不会改变程序的输出,因为“错误输入”.is_a?数值计算为假。最好的编码实践是在异常发生后使用或返回一个合理的值,以便以可接受的方式指导程序流程,因为知道发生了错误情况。
  • 无论我们在内联救援之后使用什么,'false' 甚至 'true' 或任何字符串,在 begin-rescue-end 方法中,Ruby 都不会使用,看起来如此。据我了解,任何异常都将由 MyCustomError 处理。
  • 那么为什么需要第二次救援呢?
  • 否,Float 方法抛出的所有错误都将被内联救援捕获,并且内联救援后指定的任何值 true 或 false 或字符串值都将分配给 number 变量,然后执行将继续执行,就好像什么都没有发生了。内联救援之后的下一行将评估数字变量的值,如果“number.is_a?Numeric”评估为假,MyCustomError 将被抛出,然后将立即被“rescue MyCustomError => err”语句捕获。希望这会有所帮助。
【解决方案2】:

您的unless 条件永远不会为假:Kernel#Float 将引发异常(在这种情况下甚至未达到您的条件)或返回Float(它是Numeric 的子类)。

【讨论】:

  • 如果注释掉除非条件,无论输入是什么,ruby 都会引发异常。如果 raise 行全部被注释掉,并且如果按照 sawa 的建议添加了“rescue false”,那么就不会引发任何异常。那么你会建议用什么来代替除非条件呢? raise 看起来很有必要,但不能单独存在
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-14
  • 2020-12-05
  • 2021-07-04
  • 2021-05-03
  • 1970-01-01
  • 1970-01-01
  • 2018-08-08
相关资源
最近更新 更多