Как реализовать перечислитель в Ruby?

Например:

a = [1,2,3,4,5]
a.delete_if { |x| x > 3 }

эквивалентно:

a = [1,2,3,4,5]
a.delete_if.each.each.each.each { |x| x > 3 }

Я знаю, что a.delete_if возвращает перечислитель. Но как он узнает, что должен удалить объект, когда блок each возвращает значение true? Как реализовать delete_if вручную (и в Ruby)?


person Lai Yu-Hsuan    schedule 07.10.2011    source источник
comment
[1,2,3,4,5].delete_if.each.each.each.each { |x| x > 3 } Не могли бы вы подробнее рассказать об этой строке?   -  person Matheus Moreira    schedule 07.10.2011
comment
почему delete_if.each не совпадает с each? как delete_if запоминает, что ему делать?   -  person Lai Yu-Hsuan    schedule 07.10.2011


Ответы (2)


Вы можете взглянуть на исходный код Rubinius: перечисляемый модуль

Вот пример метода отклонения:

  def reject
    return to_enum(:reject) unless block_given?

    ary = []
    each do |o|
      ary << o unless yield(o)
    end

    ary
  end
person topek    schedule 07.10.2011

В реализации delete_if код может проверять значение, возвращенное из yield, чтобы решить, следует ли удалять данную запись из массива.

Вы можете прочитать Реализация итераторов в руководстве Programming Ruby для получения более подробной информации. , но это будет выглядеть примерно так:

class Array
  def delete_if
     reject { |i| yield i }.to_a
  end
end

В приведенном выше примере используется yield для передачи каждого элемента массива в блок, связанный с вызовом delete_if, и неявно возвращается значение yield внешнему вызову reject.

person Pete    schedule 07.10.2011