Рекурсивная рутина в методе - PullRequest
1 голос
/ 17 марта 2012

Часто у меня есть рекурсивная подпрограмма в методе, который вызывается только этим методом, или в самой рекурсивной подпрограмме:

def foo
  ...
  bar
  ...
end

def bar
  ...
  bar
  ...
end

Но поскольку bar больше нигде не используется,хочу определить его как метод, но каким-то образом поместить его в метод, который вызывает его следующим образом:

def foo
  ...
  bar {# some way to mark the recursive routine
    ...
    bar # some way to call the recursive routine
    ...
  }
  ...
end

Возможно ли это?

Ответы [ 3 ]

4 голосов
/ 17 марта 2012

Легко с лямбда / proc:

def foo(n)
  fact = lambda do |i|
    i.zero? ? 1 : i * fact.call(i-1)
  end
  fact.call(n)
end

foo(4) # => 24

Вы также можете использовать защищенный или закрытый метод.

Если производительность представляет собой реальную проблему, создание объекта (лямбда) каждый раз будет медленнее, а вызов лямбды также медленнее, замыкание и все. Мой fruity драгоценный камень дает мне 3,3-кратное замедление в этом тривиальном примере; штраф должен быть намного меньше для случаев, которые действительно делают что-то более сложное. Просто убедитесь, что производительность действительно является проблемой; Вы знаете, что они говорят о преждевременной оптимизации ...

2 голосов
/ 17 марта 2012

Звучит так, будто вы пытаетесь заниматься функциональным программированием на объектно-ориентированном языке. Вы могли бы лучше обслужить, создав небольшой класс с единственной ответственностью:

class Routiner
  def foo(*args)
    # occasionally...
    do_work(some_data)
  end
protected
  def do_work(data)
    # ...work work work
    do_work(more_data) if some_condition
  end
end

Routiner.new.foo('bar', 'baz', 'bat')
0 голосов
/ 17 марта 2012

@ coreyward ответ хороший, но есть еще один прием, который вы можете использовать, чтобы ограничить область действия рекурсивной функции с помощью лямбды.

def foo
  ...
  bar = lambda do |arg|
    ...
    bar.call(...)
    ...
  end

  bar.call(...)
  ...
end

Поскольку bar имеет лексическую область действия внутри foo, никакой другой метод не можетвидеть это или называть это, но лямбда, на которую ссылается бар, может видеть бар, так как он закрывается над лексической областью, где он определен.

...