将块从一种方法传递到另一种方法

Passing block from one method to another

我需要将一个块从一个方法传递到另一个方法(我想调用 Rails.cache.fetch 并将块传递到我的方法)。

我可以将 &block 添加到参数列表并使用它将它传递给下一个方法,或者我可以创建一个新块并在其中调用 yield。我写了一个简短的例子和基准:

require "benchmark"

def with_block(&block)
  do_something 'Test', &block
end

def with_yield
  do_something('Test') { yield }
end

def do_something(string)
  "#{yield} #{string}"
end

n = 5_000_000
Benchmark.bmbm do |x|
  x.report("&block") do
    n.times { with_block { "Yo" } }
  end
  x.report("yield") do
    n.times { with_yield { "Yo" } }
  end
end


&block   3.320000   0.010000   3.330000 (  3.340438)
yield    1.670000   0.000000   1.670000 (  1.669504)
--------------------------------- total: 5.000000sec

             user     system      total        real
&block   3.270000   0.010000   3.280000 (  3.275914)
yield    1.680000   0.000000   1.680000 (  1.682768)

看起来 { yield } 方法要快得多。这是正确的方法吗?由于在新创建的块中调用 yield,是否有任何我不知道的陷阱?

简短回答:始终使用 yield,除非您有充分的理由明确引用 &block.

参见:Why blocks make ruby methods 439% slower

使用 &block,您将获得一个具体化的 Proc,您可以在其上执行各种 stuff 并且可以四处移动。但是,对于 yield 和隐式块,您只能调用该块。

通过使用 yield,解释器可以绕过所有 Proc 具体化,因为它知道开发人员将无法使用它;因此它可以只保留 C 级结构,而不必设置 Ruby 级对象。