屈服于一个匿名的块

Den*_*rdy 5 ruby

我没有理解以下行为(另请参见此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
Run Code Online (Sandbox Code Playgroud)

输出:

def_test.in
def_test ok
def_test.out
block_test.in
block_test ok
block_test.out
proc_test.in
proc_test.out
Run Code Online (Sandbox Code Playgroud)

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

Vic*_*roz 5

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

def test
  l = lambda do
    yield if block_given?
  end
  l.call
end

test { puts "In block" }
Run Code Online (Sandbox Code Playgroud)


mu *_*ort 4

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

\n\n
def def_test(&block)\n    frobnicate &block\nend\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

考虑这段简单的代码:

\n\n\n\n
def f\n    lambda do\n        puts "\\tbefore block"\n        yield if block_given?\n        puts "\\tafter block"\n    end\nend\n\nputs \'Calling f w/o block\'\nx = f; x.call\nputs\n\nputs \'Calling f w/ block\'\nx = f { puts "\\t\\tf-block" }; x.call\nputs\n\nputs \'Calling f w/o block but x with block\'\nx = f; x.call { puts "\\t\\tx-block" }\nputs\n\nputs \'Calling f w/ block and x with block\'\nx = f { puts "\\t\\tf-block" }; x.call { puts "\\t\\tx-block" }\n
Run Code Online (Sandbox Code Playgroud)\n\n

对于 1.9.2,这会产生以下结果:

\n\n\n\n
Calling f w/o block\n    before block\n    after block\n\nCalling f w/ block\n    before block\n        f-block\n    after block\n\nCalling f w/o block but x with block\n    before block\n    after block\n\nCalling f w/ block and x with block\n    before block\n        f-block\n    after block\n
Run Code Online (Sandbox Code Playgroud)\n\n

此外,Proc#call(又名proc ===)不占用块:

\n\n
\n

prc === obj \xe2\x86\x92 result_of_proc
\n 调用块,以 obj 作为 block\xe2\x80\x98s 参数。它允许一个proc对象成为case语句中when子句的目标。

\n
\n\n

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

\n\n
\n

枚举块 {|elt| ... } \xe2\x86\x92 an_enumerator

\n
\n\n

表示{...}chunk记录占用块,缺少此类符号表示Proc#callProc#call占用块。

\n\n

这并不完全是一个权威的答案,但也许它能让事情变得更清楚一些。

\n