代码之家  ›  专栏  ›  技术社区  ›  cpm

从原始范围之外的红宝石块返回

  •  2
  • cpm  · 技术社区  · 17 年前

    我想做一个看起来像这样的东西:

    def make_wrapped_block(&block)
      puts "take_block:before"
      func = lambda do
        puts "Before calling make_wrapped_block's passed block"
        block.call
        puts "After calling make_wrapped_block's passed block"
      end
      puts "take block:after"
      func
    end
    
    def make_block
      make_wrapped_block do
        puts "Before return"
        return :pi
        puts "After return"
      end
    end
    
    make_block.call
    

    make_block 生成具有类似初始化和清理功能的闭包的方法 make_wrapped_block .

    制造包装块 make_block

    [ cpm juno ~/tmp/local-jump ] ruby bad.rb
    take_block:before
    take block:after
    Before calling make_wrapped_block's passed block
    Before return
    bad.rb:15:in `make_block': unexpected return (LocalJumpError)
            from bad.rb:5:in `call'
            from bad.rb:5:in `make_wrapped_block'
            from bad.rb:20:in `call'
            from bad.rb:20
    

    现在,我可以用稍微不同的语法来实现这个想法:

    def make_wrapped_block(block)
      puts "take_block:before"
      func = lambda do
        puts "Before calling make_wrapped_block's passed block"
        block.call
        puts "After calling make_wrapped_block's passed block"
      end
      puts "take block:after"
      func
    end
    
    def make_block
      make_wrapped_block(lambda {
        puts "Before return"
        return :pi
        puts "After return"
      })
    end
    
    make_block.call
    

    这是有效的,因为当您从使用创建的匿名函数返回时 lambda ,它退出匿名函数,而 Proc.new 它试图从定义的作用域返回匿名块。你不能传递它们并安全返回。


    第二种方法效果很好,但语法比第一种版本有点难看。

    2 回复  |  直到 17 年前
        1
  •  2
  •   rampion    17 年前

    LocalJumpError :

    def make_wrapped_block(&block)
      puts "take_block:before"
      func = lambda do
        puts "Before calling make_wrapped_block's passed block"
        begin
          block.call
        rescue LocalJumpError
          # allow return / break
        end
        puts "After calling make_wrapped_block's passed block"
      end
      puts "take block:after"
      func
    end
    
    #...
    
    make_block.call
    

    但这有点难看。

    throw 相反:

    def make_wrapped_block(&block)
      puts "take_block:before"
      func = lambda do
        puts "Before calling make_wrapped_block's passed block"
        catch (:return) { block.call }
        puts "After calling make_wrapped_block's passed block"
      end
      puts "take block:after"
      func
    end
    
    def make_block
      make_wrapped_block do
        puts "Before throw"
        throw :return
        puts "After throw"
      end
    end
    

    但如果这对写你的人来说有点奇怪 make_block 方法,除非是你。

        2
  •  2
  •   zenazn    17 年前

    idiosyncrasies .

    在你的例子中,它归结为 return A. do...end 闭包不是真正的闭包(出于性能原因)。 返回 因此,不会返回 做…结束 ,但周围的方法。在其中 lambda 然而, 返回 出口出 λ 而不是预期行为的封闭方法。

    推荐文章