Le altre risposte sono piuttosto approfondite e Closures in Ruby copre ampiamente le differenze funzionali.Ero curioso di sapere quale metodo avrebbe funzionato al meglio per i metodi che facoltativamente accetta un blocco, quindi ho scritto alcuni benchmark (in corso this Paul Mucur post). Ho confrontato tre metodi:
- & blocco nella firma del metodo
- utilizzando
&Proc.new
- Wrapping
yield
in un altro blocco
Ecco il codice:
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
performance è risultata simile tra Ruby 2.0.0p247 e 1.9.3p392. Ecco i risultati per: 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)
l'aggiunta di un esplicito &block
param quando non è sempre utilizzato in realtà non rallentare il metodo. Se il blocco è facoltativo, non aggiungerlo alla firma del metodo. E, per passare i blocchi in giro, avvolgere yield
in un altro blocco è più veloce.
Detto questo, questi sono i risultati per un milione di iterazioni, quindi non preoccuparti troppo. Se un metodo rende il tuo codice più chiaro a scapito di un milionesimo di secondo, usalo comunque.
Nota a margine: 'def throry (& block)' è più autodocumentante, in particolare rispetto a un 'yield' sepolto da qualche parte in un metodo di grandi dimensioni. –