Пересылка итератора - PullRequest
4 голосов
/ 06 марта 2020

У меня есть класс (очень упрощенный ради этого обсуждения)

class MyClass
  def initialize
    @myrecs = %w(a b c d)
  end
  def each_rec
    @myrecs.each {|r| yield(r)}
  end
end

и я использую его как

x = MyClass.new
x.each_rec { |r| .... }

Так как мой метод each_rec в основном делает myrecs.each, Я хотел как-то определить, что each_rec только вперед each. Я могу достичь желаемого эффекта, явно передавая блок, то есть

def each_rec(&block)
  @myrecs.each(&block)
end

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

(1) Используйте тот факт, что each возвращает Enumerator при вызове без блока:

  def each_rec
    @myrecs.each
  end

(2) Создайте Enumerator:

   def each_rec
     @myrecs.enum_for(:each)
   end

В обоих случаях я не получил ошибку, но блок, переданный в each_rec, просто не был введен.

1 Ответ

3 голосов
/ 06 марта 2020

В Ruby, если вы вызываете Proc.new без блока внутри метода, который получил блок, он преобразует переданный блок этого метода в pro c. Итак, вы можете сделать:

class MyClass
  def initialize
    @myrecs = %w(a b c d)
  end
  def each_rec
    @myrecs.each(&Proc.new)
  end
end

x = MyClass.new
x.each_rec { |r| puts r }

и теперь вам больше не нужен явный параметр для вашего each_rec метода. Однако теперь вы должны предоставить блок методу или получить ArgumentError («попытался создать объект Pro c без блока»). Мы можем исправить это с помощью пункта охраны:

def each_rec
  return @myrecs.each unless block_given?

  @myrecs.each(&Proc.new)
end

и теперь можем использовать его так же, как each:

x = MyClass.new
x.each_rec { |r| p r }
x.each_rec.with_index { |r, i| p [r, i] }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...