change the original variable from a ruby block? [duplicate]
Possible Duplicate:
'pass parameter by reference' in Ruby?
in this example:
def test
verb = 'nothing'
yield verb
puts verb
end
test {|verb| verb = 'something'}
it will print "nothing".
is it possible to change it to "something"?
thanks
You have to remember, variables in Ruby are just references to objects. Each reference is independent of any other reference, though they may refer to the same object.
The other thing to remember is the the scope of a block is the scope it was defined in. So for your block, verb
is not in scope (because it was defined outside of the method where verb
lives).
Besides the eval-binding hack mentioned by stephenjudkins, there are two ways to do what you want. One is just to assign verb
:
def test
verb = 'nothing'
verb = yield verb
puts verb
end
This pretty directly does what you want and is really the best way to go about it.
The other way is to directly mutate the object that's passed in:
test {|verb| verb.replace 'something'}
I don't recommend this, though, because it actually changes the string itself instead of just assigning a new string to the variable. So other places where the same string object is referenced, it will contain the new text. This isn't a problem in your example, but it's a massive bug waiting to happen in any real program.
In your function, yield verb
will return the result of evaluating the block. The verb
variable in the block is not the same variable as in test
; they're different variables in different scopes. In Ruby, an assignment is an expression, so evaluating your block results in 'something', but you don't do anything with the value returned from the yield.
If, as I suspect, you want to reassign verb
in test
based on the value of the block, you'll have to do that yourself; e.g. verb = yield verb
. The assignment in the block, however, would still have no effect in test
.
Use String#replace:
def test
verb = 'nothing'
yield verb
puts verb
end
test {|verb| verb.replace('something')}
精彩评论