Yielding in an anonymous block

后端 未结 2 477
余生分开走
余生分开走 2021-01-03 01:56

I\'m not making sense of the following behavior (see also in this SO thread):

def def_test
  puts \'def_test.in\'
  yield if block_given?
  puts \'def_test.o         


        
相关标签:
2条回答
  • 2021-01-03 02:20

    block_given? considers def scope, not lambda scope:

    def test
      l = lambda do
        yield if block_given?
      end
      l.call
    end
    
    test { puts "In block" }
    
    0 讨论(0)
  • 2021-01-03 02:24

    The lambda is a closure and it seems to be capturing the block_given? and block from its outer scope. This behavior does make sense as the block is, more or less, an implied argument to the outer method; you can even capture the block in a named argument if desired:

    def def_test(&block)
        frobnicate &block
    end
    

    So the block is part of the argument list even when it isn't named.

    Consider this simple piece of code:

    def f
        lambda do
            puts "\tbefore block"
            yield if block_given?
            puts "\tafter block"
        end
    end
    
    puts 'Calling f w/o block'
    x = f; x.call
    puts
    
    puts 'Calling f w/ block'
    x = f { puts "\t\tf-block" }; x.call
    puts
    
    puts 'Calling f w/o block but x with block'
    x = f; x.call { puts "\t\tx-block" }
    puts
    
    puts 'Calling f w/ block and x with block'
    x = f { puts "\t\tf-block" }; x.call { puts "\t\tx-block" }
    

    This produces the following for me with 1.9.2:

    Calling f w/o block
        before block
        after block
    
    Calling f w/ block
        before block
            f-block
        after block
    
    Calling f w/o block but x with block
        before block
        after block
    
    Calling f w/ block and x with block
        before block
            f-block
        after block
    

    Furthermore, Proc#call (AKA proc ===) doesn't take a block:

    prc === obj → result_of_proc
    Invokes the block, with obj as the block‘s parameter. It is to allow a proc object to be a target of when clause in the case statement.

    Compare the first line with the documentation for Enumerable#chunk (for example):

    enum.chunk {|elt| ... } → an_enumerator

    The {...} indicates that chunk is documented to take a block, the lack of such notation for Proc#call indicates that Proc#call does not take a block.

    This isn't exactly an authoritative answer but maybe it clears things up a little bit.

    0 讨论(0)
提交回复
热议问题