【问题标题】:The semantic of call/cc and "ensure" in RubyRuby 中 call/cc 和“确保”的语义
【发布时间】:2013-06-11 04:10:18
【问题描述】:

据我所知,Ruby 是唯一同时支持call/cctry/catch/finally(写成begin/rescue/ensure/end 块)的主流语言。

我不熟悉 Ruby,但我的直觉告诉我这两者可能存在冲突,因为call/cc 允许任意控制流,ensure 需要一些有保证的控制流(某些代码路径必须在预定义的情况,即离开包含块)。

那么,语言中是否存在任何冲突?如果是这样,在这种情况下,语言的定义行为是什么?特别是,如果在 begin/ensure 块或 ensure/end 块中使用 call/cc 会发生什么?如果在块包含ensure 子句之后调用捕获的call/cc 怎么办?

【问题讨论】:

    标签: ruby language-design finally callcc


    【解决方案1】:

    在 Ruby 中,您有 callccthrow / catchraise / rescue / ensure

    throwensure 开始执行终止块:

    catch(:done) {
      begin
        puts "before"
        throw :done
        puts "after"  # will not be called
      ensure
        puts "ensure"
      end
    }
    

    产生:

    before
    ensure
    

    callccensure 开始跳过的块终止:

    callcc { |cc|
      begin
        puts "before"
        cc.call
        puts "after"   # will not be called
      ensure
        puts "ensure"  # will not be called
      end
    }
    

    产生:

    before
    

    另一个将Continuation 对象存储在全局变量中的示例:

    begin
      puts "before"
      callcc { |cc| $cc = cc }
      puts "after"
    ensure
      puts "ensure"
    end
    
    $cc.call
    

    产生:

    before
    after
    ensure
    after
    ensure
    after
    ...
    

    【讨论】:

    • 好的,如果我使用callcc 跳转到begin 块甚至ensure 块呢?
    • 不能跳转到任意位置,cc.call 总是跳转到callcc { } 块的末尾。
    • 我的意思是,如果我将callcc 块放在begin/end 块内,从内部返回一个函数(带有延续变量),然后从外部调用该函数,跳转到内部块?
    • 所以结论是,callcc的优先级高于ensureensure只有在没有callcc存在的情况下才能保证执行。
    猜你喜欢
    • 2011-02-16
    • 2011-08-25
    • 1970-01-01
    • 2019-12-30
    • 2017-11-14
    • 2017-01-22
    • 2016-06-05
    • 2010-12-15
    相关资源
    最近更新 更多