I have the following Ruby code:
# func1 generates a sequence of items derived from x
# func2 does something with the items generated by func1
def test(x, func1, func2)
func1.call(x) do | y |
func2.call(y)
end
end
func1 = lambda do | x |
for i in 1 .. 5
yield x * i
end
end
func2 = lambda do | y |
puts y
end
test(2, func1, func2) # Should print '2', '4', '6', '8', and '10'
This does not work, of course.
test.rb:11: no block given (LocalJumpError)
from test.rb:10:in `each'
from test.rb:10
from test.rb:4:in `call'
from test.rb:4:in `test'
from test.rb:20
Lambdas don't implicitly accept blocks like regular methods do, so your func1 can't yield. Do this instead:
func1 = lambda do |x, &blk|
for i in 1 .. 5
blk.call(x * i)
end
end
Specifically, I believe this is because yield would send control back to the caller's block, which would not include lambda invocations. So the following code works like you "expect":
def foo
(lambda { |n| yield(n) }).call(5)
end
foo { |f| puts f } # prints 5
In Ruby 1.9 only:
func1 = lambda do |x, &blk|
for i in 1..5
blk.call(x*i)
end
end
def test(x, func1, func2)
func1.call(x) do | y |
func2.call(y)
end
end
#change func1 to a method
def func1 x
for i in 1 .. 5
yield x * i
end
end
#func2 may be either a method or a lambda
#I changed it for consistency, but you don't have to
def func2 y
puts y
end
test(2, method(:func1), method(:func2))
Based upon Nikita Misharin's answer here:[https://stackoverflow.com/a/45571976/2165560], I like this:
def iterator(x)
for i in 1 .. 5
yield x * i
end
end
iteratorWrapper = -> (m,&block) { iterator(m) {|n| block.call n} }
iteratorWrapper.call(2) { |y| puts y }
It answers my question here [In Ruby, can you use the lambda or or Proc call method to invoke an iterator?.
By wrapping the iterator it can be arbitrarily passed to other methods and iterate on their blocks.
来源:https://stackoverflow.com/questions/4982630/trouble-yielding-inside-a-block-lambda