This article fornisce una buona panoramica delle differenze.
Per riepilogare l'articolo, Ruby consente blocchi impliciti ed espliciti. Inoltre, Ruby ha block, proc e lambda.
Quando si chiama
def foo(block)
end
block
è solo un semplice argomento del metodo. L'argomento è riferito nella variabile block
e il modo in cui l'interazione con esso dipende dal tipo di oggetto che si passa.
def foo(one, block, two)
p one
p block.call
p two
end
foo(1, 2, 3)
1
NoMethodError: undefined method `call' for 2:Fixnum
from (irb):3:in `foo'
from (irb):6
from /Users/weppos/.rvm/rubies/ruby-2.1.5/bin/irb:11:in `<main>'
foo(1, Proc.new { 1 + 1 }, 3)
1
2
3
Ma quando si utilizza la e commerciale &
nella definizione del metodo, il blocco assume un significato diverso. Sei esplicitamente che definisce un metodo per accettare un blocco. E verranno applicate altre regole (come non più di un blocco per metodo).
def foo(one, two, &block)
p one
p block.call
p two
end
Innanzitutto, essendo un blocco, la firma del metodo ora accetta "due parametri e un blocco", non "tre parametri".
foo(1, 2, Proc.new { "from the proc" })
ArgumentError: wrong number of arguments (3 for 2)
from (irb):7:in `foo'
from (irb):12
from /Users/weppos/.rvm/rubies/ruby-2.1.5/bin/irb:11:in `<main>'
Ciò significa, è necessario forzare il terzo argomento di essere un blocco passando il parametro con la e commerciale.
foo(1, 2, &Proc.new { "from the proc" })
1
"from the proc"
2
Tuttavia, questa è una sintassi molto rara.In rubino, metodi con i blocchi sono generalmente chiamati usando {}
foo(1, 2) { "from the block" }
1
"from the block"
2
o do end
.
foo(1, 2) do
"from the block"
end
1
"from the block"
2
Torniamo alla definizione del metodo. Ho già detto che il codice seguente è una dichiarazione di blocco esplicita .
def foo(one, two, &block)
block.call
end
I metodi possono accettare implicitamente un blocco. I blocchi impliciti sono chiamati con yield
.
def foo(one, two)
p yield
end
foo(1, 2) { "from the block" }
È possibile controllare il blocco è passato utilizzando block_given?
def foo(one, two)
if block_given?
p yield
else
p "No block given"
end
end
foo(1, 2) { "from the block" }
=> "from the block"
foo(1, 2)
=> "No block given"
Queste caratteristiche dei blocchi legati non sarebbero disponibili se si dichiara il "blocco" come un semplice argomento (quindi senza commerciale), a causa sarebbe solo un argomento metodo anonimo.
Non inserire uno spazio prima parentesi! :) –
Scusa, la mia abitudine proviene dal mondo di JavaScript :) La correggerò nel mio esempio. – wmock
http://ablogaboutcode.com/2012/01/04/the-ampersand-operator-in-ruby/ – user2864740