Ruby 在块/lambda内发生屈服故障

Ruby 在块/lambda内发生屈服故障,ruby,lambda,block,yield,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 .

我有以下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

lambda不像常规方法那样隐式接受块,因此您的
func1
无法生成。改为这样做:

func1 = lambda do |x, &blk|
  for i in 1 .. 5
    blk.call(x * i)
  end
end
具体地说,我认为这是因为yield会将控制权发送回
调用方的块,该块不包括lambda调用。因此,以下代码的工作方式与“expect”类似:

仅在Ruby 1.9中:

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

根据Nikita Misharin的回答:[,我喜欢这样:

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 }
它回答了我的问题


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

@wuputah:你说得对。我在1.8.7新闻文件中看到了此功能的介绍。但是,它附带了一个警告“当前形状的这个实现被认为是有缺陷的,特别是在嵌套块调用时。把它作为一个实验性的特性。"@肯·布鲁姆:不错,我不知道!跟稳定的Ruby发行版中的实验性功能完全不同。@wuputah:Ruby 1.8.7中大量的更改是Ruby社区感到震惊的一大原因。我不知道1.8.7中有失败的实验性更改,但考虑到他们对1.8.7在新版本中进行如此多的更改的不负责任首先,我想他们也会加入一些失败的实验版本也就不足为奇了由于此功能在v1.8.7中是实验性的,我应该尽量避免多少?例如,让
func1
返回一个包含其生成值的数组是否会更好,在该数组中,我将对数组值分别运行
func2
?您应该了解,这实际上是一个更复杂的al的简化版本如果没有严重的内存压力,我会强烈地考虑返回一个生成的值数组。它不仅避免了实验语言的特征,而且可能更清楚地发生了什么。也许你可以分享更复杂的算法,这样我们就可以帮助你做出决定?可能的DUPL。副本
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))
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 }