其他答案非常彻底,Ruby中的Closures广泛涵盖了功能差异。我很好奇哪种方法对于可以接受块的方法最有效,所以我写了一些基准测试(参考Paul Mucur的文章)。我比较了三种方法:
- &阻止方法签名
- 使用 &Proc.new
- 包装yield在另一个块中
这是代码:
require "benchmark"
def always_yield
  yield
end
def sometimes_block(flag, &block)
  if flag && block
    always_yield &block
  end
end
def sometimes_proc_new(flag)
  if flag && block_given?
    always_yield &Proc.new
  end
end
def sometimes_yield(flag)
  if flag && block_given?
    always_yield { yield }
  end
end
a = b = c = 0
n = 1_000_000
Benchmark.bmbm do |x|
  x.report("no &block") do
    n.times do
      sometimes_block(false) { "won't get used" }
    end
  end
  x.report("no Proc.new") do
    n.times do
      sometimes_proc_new(false) { "won't get used" }
    end
  end
  x.report("no yield") do
    n.times do
      sometimes_yield(false) { "won't get used" }
    end
  end
  x.report("&block") do
    n.times do
      sometimes_block(true) { a += 1 }
    end
  end
  x.report("Proc.new") do
    n.times do
      sometimes_proc_new(true) { b += 1 }
    end
  end
  x.report("yield") do
    n.times do
      sometimes_yield(true) { c += 1 }
    end
  end
end
Ruby 2.0.0p247和1.9.3p392之间的性能相似。这是1.9.3的结果:
                  user     system      total        real
no &block     0.580000   0.030000   0.610000 (  0.609523)
no Proc.new   0.080000   0.000000   0.080000 (  0.076817)
no yield      0.070000   0.000000   0.070000 (  0.077191)
&block        0.660000   0.030000   0.690000 (  0.689446)
Proc.new      0.820000   0.030000   0.850000 (  0.849887)
yield         0.250000   0.000000   0.250000 (  0.249116)
在&block不经常使用的情况下添加显式参数确实会使该方法变慢。如果该块是可选的,则不要将其添加到方法签名中。而且,要在块之间传递,包裹yield在另一个块中最快。
就是说,这些是一百万次迭代的结果,所以不必太担心。如果一种方法花费一秒钟的百万分之一来使代码更清晰,则无论如何都要使用它。