问题描述
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.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 变量并直接调用它,但我更希望弄清楚为什么我最终需要这样做.>
I don't mind resorting to explicitly declaring the &block variable and calling it directly, but I'd more ideally like to make some sense of why I end up needing to.
推荐答案
lambda
是一个闭包,它似乎正在捕获 block_given?
并阻止其外部范围.这种行为确实有意义,因为块或多或少是外部方法的隐含参数;如果需要,您甚至可以在命名参数中捕获块:
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.
考虑这段简单的代码:
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 中生成以下内容:
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
此外,Proc#call
(AKA proc ===
) 不需要一个块:
Furthermore, Proc#call
(AKA proc ===
) doesn't take a block:
prc === obj → result_of_proc
调用块,使用 obj 作为块的参数.就是让一个proc对象成为case语句中when子句的目标.
将第一行与 Enumerable#chunk的文档进行比较代码>
(例如):
Compare the first line with the documentation for Enumerable#chunk
(for example):
enum.chunk {|elt|... } → an_enumerator
{...}
表示 chunk
被记录为占用一个块,Proc#call
缺少这样的符号表示Proc#call
不需要一个块.
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.
这篇关于在匿名块中屈服的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!