Проблемы, уступающие внутри блока / лямбда - PullRequest
8 голосов
/ 13 февраля 2011

У меня есть следующий код 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 ]

12 голосов
/ 13 февраля 2011

Lambdas неявно принимают блоки, как это делают обычные методы, поэтому ваш func1 не может дать. Сделайте это вместо:

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

В частности, я считаю, что это происходит потому, что yield отправляет управление обратно в блок caller, который не включает лямбда-вызовы. Поэтому следующий код работает так, как вы ожидаете:

def foo
  (lambda { |n| yield(n) }).call(5)
end
foo { |f| puts f }  # prints 5
4 голосов
/ 13 февраля 2011

Только в Ruby 1.9:

func1 = lambda do |x, &blk|
  for i in 1..5
    blk.call(x*i)
  end
end
1 голос
/ 13 февраля 2011
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))
0 голосов
/ 08 августа 2017

На основании ответа Никиты Мишарина здесь: [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 }

Он отвечает на мой вопрос здесь [ В Ruby, можете ли вы использовать лямбда-или или метод вызова Proc для вызова итератора? .

Оборачивая итератор, он может быть произвольно передан другим методам и перебрать их блоки.

...