在块/ lambda中产生麻烦

时间:2011-02-13 05:33:29

标签: ruby lambda block yield

我有以下Ruby代码:

# 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'

当然,这不起作用。

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

4 个答案:

答案 0 :(得分:12)

Lambda不会像常规方法那样隐式接受块,因此func1无法屈服。这样做:

func1 = lambda do |x, &blk|
  for i in 1 .. 5
    blk.call(x * i)
  end
end

具体来说,我认为这是因为yield会将控制权发送回caller的块,这不包括lambda调用。所以下面的代码就像你“期待”一样:

def foo
  (lambda { |n| yield(n) }).call(5)
end
foo { |f| puts f }  # prints 5

答案 1 :(得分:4)

仅限Ruby 1.9:

func1 = lambda do |x, &blk|
  for i in 1..5
    blk.call(x*i)
  end
end

答案 2 :(得分:1)

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))

答案 3 :(得分:0)

基于Nikita Misharin在这里的答案:[https://stackoverflow.com/a/45571976/2165560],我喜欢这个:

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 }

它在这里回答了我的问题[In Ruby, can you use the lambda or or Proc call method to invoke an iterator?

通过包装迭代器,它可以任意传递给其他方法并迭代它们的块。