为什么这个异常没有被救援块捕获?

Pra*_*al1 2 ruby

我运行了这个代码:

begin
  print 'Enter something:'
  x = gets.to_i          # Enter a string
rescue => err
  print(err.to_s)
end
Run Code Online (Sandbox Code Playgroud)

我不明白为什么救援块没有捕获异常。当输入字符串时它总是返回零,并且不会触发救援块。我不知道为什么它不起作用。有人可以帮忙吗?

Tod*_*obs 5

String#to_i 和 Kernel#Integer 之间的行为不同

您的异常处理程序从未被调用的原因是String#to_i不会引发异常,即使它无法检测到 String 对象中的有效整数。在这种情况下,它只会返回0。

相比之下,Kernel#Integer的行为更复杂,但如果字符串的内容不严格符合数字表示,则预计会引发 ArgumentError 或 TypeError 。

因此,最小化重构现有代码以在非数字输入上引发异常:

begin
  print 'Enter something: ' 
  x = Integer gets
rescue => err
  # Do something other than just print err on STDERR, which is the 
  # default behavior anyway. Perhaps send it to STDOUT instead.
  puts "I received an exception: #{err}"

  # After handling, re-raise the original exception with or without
  # passing the original exception object. `raise` and `raise err` 
  # will do the same thing here.
  raise

  # For more advanced uses, you can also do something else like raise 
  # a different exception (e.g. TypeError), or modify the exception
  # object stored in err and raise that modified object instead.
end
Run Code Online (Sandbox Code Playgroud)

以下用户输入都将干净利落地转换:

  • 1
  • 2
  • 0xff

在大多数情况下,该代码甚至可以处理初始/尾随空格、换行符和回车,而无需您做任何额外的工作。然而:

  • 输入一些内容:一个
    ArgumentError: invalid value for Integer(): "one\n"

  • 输入内容:“1”
    ArgumentError:Integer() 的值无效:“\”1\“\n”

  • 输入内容:nil
    ArgumentError:Integer() 的值无效:“nil\n”

通常,您可以依靠 Kernel#Integer 在必要时引发异常,这会大大简化您的代码。但是,请参阅下面的警告。

注意事项

这些示例不需要它,但您可能还想在必要时使用 #strip、#chomp 或其他字符串转换来清理您的输入。您在这方面的进展将因您的实际用例而有很大差异,但是虽然 Kernel#Integer 通常会做正确的事情,并且 Ruby 鼓励依靠异常来处理非标准的边缘情况,但信任受用户污染的输入通常是不明智的.

还值得注意的是 String#to_i 和 Kernel#Integer 都可能对用户输入以外的值进行操作,在这种情况下,知道Integer(nil)会引发:

整数零类型错误
:无法将零转换为整数

这可能很重要。同样,您的里程可能会有所不同。

  • @Practical1 不需要谢谢。赞成票和接受的答案是 Stack Exchange 上的升值货币。:) 评论主要是为了澄清。 (2认同)