2.5. 核心语言——错误处理
Ruby 使用异常来处理错误。
Raise关键字
Raise 这个关键字后面跟的就是错误类型的名字,还有一个 message 紧接着就抛出这个错误。Raise 它会终止当前的方法以及调用这个的方法。然后在堆栈里依次往上,直到一个 rescue 子句出现。
raise NameError, "that's not my name"
begin 和 rescue 关键字
为了捕获潜在的异常,使用 begin 和 rescue 关键字。这个结构就跟其他语言里面你可能遇到的 try/catch 指令是差不多的,它是从 begin后的指令开始运行,直到其中一个指令产生异常。如果异常发生,这个时候 rescue 这个区块就将被执行。
begin
set_name('jim')
rescue
puts "sth bad happened"
end
rescue + 箭头 + 变量
你可以在 rescue 的后面选择性的加一个箭头和变量,这个时候异常对象就将绑定到这个变量上。
begin
set_name("Jim")
rescue => error
puts error.message
end
rescue + 错误类型名称 + 箭头 + 变量
rescue 还可以跟错误类型的名称,然后 Ruby 将根据异常与每个 rescue 子句后的错误类型进行匹配的结果,来决定执行哪个区块。
begin
set_name("Jim")
rescue NameError => error
puts "bad name: #{error.message}"
rescue TypeError => error
puts "bad type: #{error.message}"
end
方法体中,begin 和 end 可以省略
在一个方法体中(我们这个 def 和 end 之间就是方法体),变量处理的 begin 和 end 都是可以省略的。如果一个方法体包含了一个 rescue 子句,那么它就表现得像整个方法体已经被 begin 和 end 包裹了一样。
def foo
do_something(x)
rescue => e
handle_error(e)
end
foo
retry 关键字
在一个 rescue 子句里面,如果还含有 retry 这个关键字,就会使 begin 这一部分重新从头执行。
begin
set_name("Jim")
rescue
puts "something bad happened"
retry
end
这个会不停执行 begin 区块,就不演示了
ensure 子句
在错误处理区块中,除了 rescue 子句外还可以包括 ensure 子句——类似于其他语言中的 Finally,这里面定义了不管是否有错误抛出都会被执行的代码,对清理资源是很有用的。
begin
file = File.open("config.json")
config = JSON.parse(file.read)
rescue
puts "invalid JSON"
ensure
file.close
end
Ruby 内置错误对象
Ruby 还有很多内置的错误对象以及库的自定义错误。 Errno 模块就定义了各种代表底层 C 系统代码中的低级错误的错误。比如如果你打开一个并不存在的文件,一个 Errno::ENOENT 错误就将被产生。
*Errno 模块
Ruby 的异常对象是 exception 的子类。然而操作系统通常都是使用普通的整数来报告错误的。这个 Errno 模块就是用来动态的将这些操作系统错误映射到 Ruby 的类。因为这个子类是在这个 Errno 模块里面创建的,所以说它的名称应该是以 Errno:: 开头。这些 Errono:: 类的名字都是跟 Ruby 所处的环境有关。在一个典型的 UNIX 或者 Windows 平台上,有比如像 Errno::EACCES
, Errno::EAGAIN
, Errno::EINTR
等等。
如果要获取对应于一个特定错误的操作系统 error number 的话,就可以通过这个类的常数 Errno::
error::Errno
来获得:
Errno::EACCES::Errno #=> 13
Errno::EAGAIN::Errno #=> 11
Errno::EINTR::Errno #=> 4
特定平台上操作系统错误的完整列表可以通过 Errno.constants
得到:
Errno.constants