屈服于一个匿名的块

我没有理解以下行为(另请参见此SO线程 ):

def def_test puts 'def_test.in' yield if block_given? puts 'def_test.out' end def_test do puts 'def_test ok' end block_test = proc do |&block| puts 'block_test.in' block.call if block puts 'block_test.out' end block_test.call do puts 'block_test' end proc_test = proc do puts 'proc_test.in' yield if block_given? puts 'proc_test.out' end proc_test.call do puts 'proc_test ok' end 

输出:

 def_test.in def_test ok def_test.out block_test.in block_test ok block_test.out proc_test.in proc_test.out 

我不介意明确声明&block变量并直接调用它,但我更理想地想了解为什么我最终需要它。

lambda是一个闭包,它似乎捕获了block_given? 并阻止其外部范围。 这种行为确实有意义,因为块或多或少是外部方法的隐含参数; 如果需要,您甚至可以在命名参数中捕获块:

 def def_test(&block) frobnicate &block end 

所以即使没有命名,该块也是参数列表的一部分。

考虑一下这段简单的代码:

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

这为1.9.2产生了以下内容:

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

此外, Proc#call (AKA proc === )不会阻止:

prc === obj→result_of_proc
调用块,使用obj作为块的参数。 它允许proc对象成为case语句中when子句的目标。

将第一行与Enumerable#chunk的文档进行比较(例如):

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

{...}表示chunk被记录为占用块,缺少Proc#call的这种表示法表示Proc#call不占用块。

这不是一个权威的答案,但也许它可以解决一些问题。

block_given? 考虑def范围,而不是lambda范围:

 def test l = lambda do yield if block_given? end l.call end test { puts "In block" }