Ruby 中的错误处理 ( 上 )

yufei       6 年, 3 月 前       1544

除了 Ruby 基础教程 的翻译之外,好久没接触到 Ruby 语言的一些知识了。这次一时兴起,想讲讲 Ruby 的一些知识,找来找去,还是决定从 错误处理 ( error handling ) 开始。

本章节,我们将会涉及到一下几个知识点:

  1. Ruby 中的错误 ( error ) 是什么 ?
  2. 怎样抛出 ( throw ) 和 捕获 ( catch ) 一个错误。
  3. 错误和一些魔法变量。

Ruby 中的错误是什么?

这看起来简直就是一个非常简单的问题,简单到感觉都不用再来讲解一次 。 but ,真的是这样么 ?

众所周知, Ruby 是一个完全面向对象的语言。所以呢,哪怕是一个错误,也是某个类的实例,而且这个类必须有一个特殊的祖先类 Exception ( 不一定是父类 )。

例如,我们可以在 irb ( Ruby 的交互式解释命令行工具) 中输入以下内容来看看各种系统级错误是否是 Exception 的实例

irb> RuntimeError.ancestors.include? Exception
 => true
irb> NoMethodError.ancestors.include? Exception
 => true

这也是为什么通常把 Ruby 中的错误称之为 「 异常 」( Exception ) 的原因。

由于错误也是一个类,因此,Ruby 提供了一堆实例方法来处理错误。这些方法都在 Exception 中定义,且可以被所有子类使用。

例如,Exception#backtrace 方法返回错误堆栈,而 Exceptio#message 方法则返回与错误关联的摘要消息。

如果你想了解 Exception 类的更多信息,目前只有去访问官方文档。我们网站,会在适当的时候 ( 主要看心情 ) 撰写一些文章来解释解释。

怎么抛出 ( throw ) 和捕获 ( catch ) 一个错误

别的语言有的功能,在 Ruby 中只会更多而不会更少,像捕获异常这种机制,我们的大 Ruby 也是有的,Kernel#raise 方法就用来负责在 Ruby 中引发 ( 抛出 ) 错误

irb> raise 'an error occurred'
RuntimeError: an error occurred
irb> raise NoMethodError, 'an error occurred'
NoMethodError: an error occurred

上面的代码中,当第一次调用 Kernel#raise 方法时,可以看到该方法抛出了一个 运行时错误 ( RuntimeError ) ,这是默认错误类型。 因为我们并没有对传递其它的错误类型作为参数

相反,在第二次调用 Kernel#raise 时,引发的异常是 NoMethodError - 因为我们将它定义为方法调用的第一个参数。

捕获错误

当然了,抛出了错误就要对错误进行处理,不然系统和应用会崩溃的,也就是停止运行。

Ruby 则提供了 begin ... end 中的 resuce 字句用于捕获 ( catch ) 错误

begin
  raise NoMethodError, 'an error occurred'
rescue NoMethodError => e
  puts "#{e.class}: #{e.message}"
end

运行结果为 NoMethodError: an error occurred

上面的代码中,rescue 子句捕获了在 begin ... end 块中调用 Kernel#raise 方法引发的NoMethodError 异常

begin ... end 块可以也通常用于根据每个代码块可能发生的错误划分代码块

begin
  3 / 0
rescue ZeroDivisionError => e
  puts "#{e.class}: #{e.message}"
end

begin
  "my string".odd?
rescue NoMethodError => e
  puts "#{e.class}: #{e.message}"
end

上面的代码输出结果如下

ZeroDivisionError: divided by 0
NoMethodError: undefined method `odd?' for "my string":String

请注意,在第一个 begin ... end 块中,3/0 是一个除零错误,是通过 Ruby 中的 Integer#/ 方法在内部抛出的一个 ZeroDivisionError

而第二个 begin ... end 块,因为调用了一个不存在的方法 BasicObject#method_missing ,所以 Ruby 抛出了 NoMethodError 错误。

错误和魔法变量

刚刚我们看到了如何使用 rescue 关键字来捕获异常。其实,除了参数 e 之外,Ruby 会给两个特殊的魔法变量赋值,方便我们在捕获错误时对错误进行处理。

  • $! 变量包含了抛出的异常实例
  • $@ 变量则包含了抛出错误时的堆栈实例

这两个变量的使用方法一般如下

begin
  "my string".odd?
rescue NoMethodError => e
  puts "#{$!.class}: #{$!.message}"
  $@.each { |loc| puts loc }

  # SAME AS
  # puts "#{e.class}: #{e.message}"
  # e.backtrace.each { |loc| puts loc }
end

运行结果如下

NoMethodError: undefined method `odd?' for "my string":String
/workspace.rb:87:in `eval'
/workspace.rb:87:in `evaluate'
...
/bin/irb:11:in `<main>'

需要注意的是,$!$@ 两个变量只存在于 rescue 块中,超出了这个块就会被设置为 nil

结束语

好的知识点,文章不在于重复不重复,而是每次阅读的时候,都有新的感悟

目前尚无回复
简单教程 = 简单教程,简单编程
简单教程 是一个关于技术和学习的地方
现在注册
已注册用户请 登入
关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.