【发布时间】:2016-04-20 10:28:11
【问题描述】:
我需要将一个块从一种方法传递给另一种方法(我想调用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,是否有任何我不知道的问题?
【问题讨论】:
-
您拥有
Proc,以及您也可以使用的专用Proc,即lambda。方法也是一个块,但最初不是一个对象。您可以将方法转换为Method对象。您有更多的选择,而不仅仅是通过块的两种方式。所以我认为你的问题有些不完整。传递匿名块没有特殊考虑,除了不按名称访问它(即在方法之外),尽管我认为 Procs 和 lambdas 都被认为是“匿名的”。 -
yield确实更快。正是因为它的功能较少。您只能调用传递的块。例如,您不能将其传递给下一个方法。顺便说一句,您的测试没有意义。do_something不使用该块。 -
@SergioTulentsev 你可以通过调用它来传递它。
class Array; def my_map; map{|e| yield(e)} end end. -
@sawa:这没有通过。这将创建一个完全不相关的块,其中包含所有产生的(语法)开销。与
def my_map(&block); map(&block); end比较。 -
@sawa:因此,现在中间方法被底层方法的实现细节(其块签名)污染了。