在 Ruby 中的错误处理 ( 上 ) 章节中我们学习了 Ruby 的错误处理的一些基础知识,其实,这已经能够应付 50% 的情况了,相比于其它的语言教程,我们似乎还漏了一个最重要的东西没讲解,那就是自定义错误 ( custom error )。
但,就这些了吗?
不是,Ruby 还提供了另一个非常有意思的关键字 retry
用来重入触发了错误的代码块。
本章节,我们对这两个知识点做一些简单的介绍。
retry 关键字
retry
关键字用于重新执行 begin ... end
块中包含的代码。例如下面的代码,当 i 的值小于 3 的时候就会重新执行一次
i = 0 begin i += 1 puts "retry ##{i}" raise RuntimeError rescue RuntimeError => e retry if i < 3
输出结果如下
retry #1 retry #2 retry #3
注意,重新执行并不是重置执行,因为 i 变量在外部定义,当第一次执行时会输出 retry #1
然后抛出了异常
当使用 retry
关键字重新执行时,此时的 i 已经通过 i += 1
增长到了 2
。以此类推,直到 i > 3
再也不满足重新执行的条件了,所以最终的输出结果如上,而不是
retry #1 retry #1 retry #1
当然了,如果把 i=0
放入 begin
语句,会报错的。
需要注意的另一点是,begin ... rescue ... end
子句可以访问调用范围的变量。
但,retry
关键字只能在 rescue
内部调用,否则会抛出一个 SyntaxtError
错误,例如下面的代码
irb> retry SyntaxError: Invalid retry
自定义错误
Ruby 内置的错误已经能满足大部分的要求,但总有那么几次,需要能够自己定义错误,尤其是在开发框架的时候。
前一章节中我们提到,所有的 Ruby 错误,都必须有一个 Exception
祖先。这句话反过来也适用,就是,包含了 Exception 类作为祖先的类,都可以作为一个错误被 raise
抛出。
也就是说,我们可以通过简单地声明一个继承自其祖先链中包含 Exception 类的类的新类来创建新的错误类型
class PolicyError < Exception end class UserPolicyError < PolicyError end begin raise PolicyError, 'access not granted' rescue PolicyError => policy_error puts "#{policy_error.class}: #{policy_error.message}" end begin raise UserPolicyError, 'user unauthorized' rescue UserPolicyError => user_policy_error puts "#{user_policy_error.class}: #{user_policy_error.message}" end
运行结果如下
PolicyError: access not granted UserPolicyError: user unauthorized
上面的代码中,UserPolicyError
直接继承自 PolicyError
类,而 PolicyError
类直接从 Exception
继承。
你有没有尝试过,当使用 raise
抛出一个祖先中不包含 Exception
类的类会怎么样 ?
直接上代码试一下就知道结果了呗,哈哈
class NotAnError end raise NotAnError
输出结果如下
TypeError (exception class/object expected)
也就是说,如果 Kernel#raise
方法抛出的错误类的祖先中不包含 Exception ,则会抛出另一个错误 TypeError
结束语
我本以为自己会讲解的很透彻,结果讲解的超级肤浅。哎