Книга: Программирование на языке Ruby

8.3.6. Энумераторы

8.3.6. Энумераторы

Объект класса Enumerator — по существу, обертка, превращающая итераторный метод в полноценный объект Enumerable. Обернутый таким способом итератор приобретает все методы и свойства, присущие перечисляемым структурам.

В следующем искусственном примере в классе Foo есть итератор и больше ничего. Да и сам-то итератор не делает ничего полезного, только четыре раза вызывает yield. Чтобы подчеркнуть особенность его работы, итератор назван every, а не each.

require 'enumerator'
class Foo
 def every
  yield 3
  yield 2
  yield 1
  yield 4
 end
end
foo = Foo.new
# Передается объект и имя итератора...
enum = Enumerable::Enumerator, new(foo, :every)
enum.each {|x| p x } # Печатаются элементы
array = enum.to_a    # [3,2,1,4]
sorted = enum.sort   # [1,2,3,4]

Преобразование выглядит загадочно, но, по сути, это не что иное как:

enum = []
foo.every {|x| enum << x }

В примере выше enum — настоящий массив, а не просто объект Enumerator. Как следствие, несмотря на некоторые тонкие различия, это еще один способ преобразовать объект в перечисляемую структуру Enumerable.

Если затребована библиотека enumerator, то в классе object появляется метод enum_for. Поэтому создание объекта в первом примере можно записать компактнее:

enum = fоо.enum_for(:every)

Мы уже видели, как итераторы each_slice и each_cons позволяют осуществлять обход с группировкой. Оказывается, что есть специальные методы enum_slice и enum_cons, которые создают из таких итераторов объекты-энумераторы (по существу, трансформируя имя итератора в each). Имейте в виду, что методы Enumerable::Enumerator.new и enum_for могут принимать необязательный список аргументов в качестве последнего параметра. Ниже мы воспользовались этим для передачи итератору «размера окна»:

array = [5,3,1,2]
discrete = array.enum_slice(2)
# To же, что Enumerable::Enumerator.new(array,:each_slice,2)
overlap = array.enum_cons(2)
# To же, что Enumerable::Enumerator.new(array,:each_cons,2)
discrete.each {|x| puts x.join(",") }
# Выводится:
# 5,3
# 1,2
overlap.each {|x| puts x.join(",") )
# Выводится:
# 5,3
# 3,1
# 1,2

Оглавление книги


Генерация: 2.125. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз