Why is the parameter of this method a lambda and how does it work
Taken from Programming ruby 1.9 book:
def my_while(cond, &body)
while cond.call
body.call
end
end
a=0
my_while -> { a < 3 } do
puts a
a += 1
end
produces:
0
2
The method expects an explicit parameter cond
, and this "condition" is assumed to be a lambda/proc (the assumption is made by relying on cond.call
to succeed) and has to be passed to the method my_while
explicitly. The &
syntax captures a method's block (if present) in a variable by implicitly converting it to a Proc
object (see 'The ampersand').
Blocks are not real objects in Ruby and thus have to be converted by using the ampersand syntax. Once the block is bound to a Proc, you can send the call
message on it as on any other proc/lambda.
The ->
syntax is short for lambda
, which converts a block to a Proc object (explicitly). There is also a slight difference between using lambda and Proc.new. Again, the wikibook:
Actually, there are two slight differences between lambda and Proc.new.
First, argument checking. The Ruby documentation for lambda states: Equivalent to Proc.new, except the resulting Proc objects check the number of parameters passed when called.
Second, there is a difference in the way returns are handled from the Proc. A return from Proc.new returns from the enclosing method (acting just like a return from a block, more on this later):
def try_ret_procnew
ret = Proc.new { return "Baaam" }
ret.call
"This is not reached"
end
# prints "Baaam"
puts try_ret_procnew
While return from lambda acts more conventionally, returning to its caller:
def try_ret_lambda
ret = lambda { return "Baaam" }
ret.call
"This is printed"
end
# prints "This is printed"
puts try_ret_lambda
With this in light, I would recommend using lambda instead of Proc.new, unless the behavior of the latter is strictly required. In addition to being way cooler a whopping two characters shorter, its behavior is less surprising.
The piece -> { a < 3 }
is a shortcut for a lambda term (which was introduced with ruby 1.9). This is the first parameter passed to your method (i.e. cond
) while the block afterwards is assigned to body
. The lambda is then executed inside your method via cond.call
.
精彩评论