我没有理解以下行为(另见in this SO thread):
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变量并直接调用它,但我更理想的是要理解为什么我最终需要。
答案 0 :(得分:5)
block_given?
考虑def
范围,而非lambda
范围:
def test
l = lambda do
yield if block_given?
end
l.call
end
test { puts "In block" }
答案 1 :(得分:4)
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 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" }
这为我提供了以下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
此外,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
没有阻止。
这不是一个权威性的答案,但也许它可以解决一些问题。