[2014年学习计划之RoR系列] 第二步 – 熟悉Ruby语言 (3/n)

Ruby中的异常处理

Ruby预定义了常见的异常类型,如下图所示:


所有的异常类都从基类Exception派生出来,这一点跟Java, C#, Python都是类似的。

Ruby特别点的地方 - 当有异常发生时,ruby会将与这个异常相关联的的异常对象放到全局变量$!中去。(这段有点不那么清晰,理解中。。。附上原文吧)

When an exception is raised, and independent of any subsequent exception handling, Ruby places a reference to the associated Exception object into the global variable $!(The exclamation point presumably mirroring our surprise that any of our code could cause errors).

异常处理的例子:

begin
    eval string
rescue SyntaxError, NameError => boom
    print "String doesn't compile: " + boom
rescue StandardError => bang
    print "Error running script: " + bang
end

Ruby使用的是rescue关键字过滤异常,不同于其他语言中常见的catch。在begin块中可以有多个rescue,而且每个rescue可以有多个异常类型。

如果rescue后边没有类型参数,那么Ruby使用StandardError作为缺省值。

系统错误

在POSIX系统上,errno是一个事实上的标准。系统或应用程序都使用errno来报告错误。Ruby将这些错误包装成异常,这些异常类都是派生自SystemCallError。我们可以从类名上看出它们,例如Errno::EIO, Errno::EGAAIN等等。

这些类的Errno字段可以一一对应系统的errno值。

Errno::EAGAIN::Errno35
Errno::EPERM::Errno1
Errno::EIO::Errno5
Errno::EWOULDBLOCK::Errno35
  

 

有了try/catch,那么有没有finally?

这个可以有。ensure就是我们要的东西。很直白,就不说了吧。

f = File.open("testfile")
begin
    # .. process
rescue
    # .. handle error
ensure
    f.close unless f.nil?
end

再来看点特别的东西 – else

f = File.open("testfile")
begin
    # .. process
rescue
    # .. handle error
else
    puts "Congratulations no  errors!"
ensure
    f.close unless f.nil?
end

rescue后面的else子句会在没有异常抛出的时候被执行到。- 好像这个真没什么用啊。

下面上点有用的耍耍。

@esmtp = true
begin
    # First try an extended login. If it fails because the
    # server doesn't support it, fall back to a normal login
    if @esmtp then
        @command.ehlo(helodom)
    else
        @command.helo(helodom)
    end
rescue ProtocolError
    if @esmtp then
        @esmtp = false
        retry
    else
        raise
    end
end

有意思的地方就是那个红色加粗的retry。上面这段代码先将esmtp设置为true试着登陆,如果不成功就置为false重试。嗯,我觉得还是挺有用的。

说完了怎么捕获异常,下面该轮到抛出异常

raise
raise "bad mp3 encoding"
raise InterfaceException, "Keyboard failure", caller

这里的raise实际上是Kernel.raise方法。

第一个raise没有带任何参数,它用来将当前的异常再向外层抛出。如果当前没有异常,那么将会抛出一个RuntimeError。

第二个raise带有一个字符串参数,这个参数被用来构造一个RuntimeError的异常,然后被抛出。

第三个raise带有3个参数,第一个是异常类型,第二个是异常的消息,第三个是call stack。Kernel.caller用来产生调用堆栈。

Ruby中真真儿的catch/throw是这样用滴

当有错误发生的时候,如何从层层负责逻辑中跳出来?C-style longjump? No, Ruby提供了catch/throw的方便用法。

catch (:done) do
    while line = gets
        throw :done unless fields = line.split(/\t/)
        songlist.add(Song.new(*fields))
    end
    songlist.play
end

catch在这里定义了一个名字为done的代码块,这个代码块正常执行直到遇到异常或正常结束。

又一个例子:

def prompt_and_get(prompt)
    print prompt
    res = readline.chomp
    throw :quit_requested if res == "!"
    res
end

catch :quit_requested do
    name = prompt_and_get("Name: ")
    age = prompt_and_get("Age: ")
    sex = prompt_and_get("Sex: ")
    # ..
    # process information
end

春节前的ruby笔记就到这里了。祝大家马上有钱,马上有房,马上有对象。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bruce Jia(上海)

熬夜码字换酒钱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值