Closures in Ruby
Sample code:
def func(a, &closure)
return a if a
closure ||= lambda{ |words| puts "!!! " + words }
closure.call("1")
closure.call("2")
end
func(false){ |words| puts "??? " + words }
Please explain. I can not understand this line:
closure ||= lambda{ |wor开发者_运维知识库ds| puts "!!! " + words }
If you remove ||
will be permanently displayed as follows: "!!! 1", "!!! 2"
. Why?
And also explain this:
def func(a, &closure)
where did &closure
.
def func(a, &closure)
return a if a
closure ||= lambda{ |words| puts "!!! " + words }
closure.call("1")
closure.call("2")
end
func(false){ |words| puts "??? " + words }
In "&closure" the ampersand (&) means that the function takes a block as a parameter. What is happening is you are passing a Proc (a block is just a Proc defined with a different syntax) to the func function which is then called with the variable 1 and 2.
The ||= means "or equals." It is used to assign a value to a variable if the current value is nil. It is shorthand for:
closure = lamda{ |words| puts "!!! " + words } if closure.nil
This blog post explains blocks, Procs and lamdas well.
The token closure
here does not have any significance at all. It is just a local block variable given as an argument. When func
is used with a block, closure
will refer to that block. If not, it will initially be nil
. What ||=
does is, when the variable is nil
, it assigns what comes to the right. So if you use func
with a block, closure
will be that block; if you use it without a block, closure
will be lambda{...}
. Now, if you replace ||=
with =
, then closure
will always be lambda{...}
irrespective of whether you use it with a block. closure.call(1)
will substiture 1
to words
in closure
, and you will get the output !!!1
; similarly with closure.call(2)
, which outputs !!!2
.
This is nothing to do with the closures
closure ||= lambda{ |words| puts "!!! " + words }
|| says that, if the variable closure alreay initialized just use it, otherwise initialize the new lambda ambda{ |words| puts "!!! " + words }
since you are passing the lambda already
func(false){ |words| puts "??? " + words }
default lambda (having !!!) not initialized
But if you remove the ||, it always initialize the new lambda
You can print the !!! without removing ||, just call
func(false)
精彩评论