0Pricing
Ruby Academy · Урок

Написание собственного each

Реализуйте итерацию

«Написание собственного each» — бесплатный урок Ruby Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Ruby Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Ruby Academy содержит 4 уроков всего.

Реализация итерации

Итерация в Ruby строится вокруг одного метода: each. Написав собственный each, Вы определяете, как обходится коллекция, и открываете доступ ко всей экосистеме итерации.

class Trio
  def each
    yield 1
    yield 2
    yield 3
  end
end
Trio.new.each { |n| puts n }

each передаёт значения

Внутри each вызывайте yield один раз для каждого элемента. Блок, переданный вызывающим кодом, по очереди получает каждое значение.

class Days
  NAMES = ["Mon", "Tue", "Wed"]
  def each
    NAMES.each { |d| yield d }
  end
end
Days.new.each { |day| puts day }

Хранение внутренних данных

Обычно each обходит данные, хранящиеся в переменной экземпляра.

class Stack
  def initialize
    @items = []
  end
  def push(x); @items << x; self; end
  def each
    @items.each { |i| yield i }
  end
end
s = Stack.new
s.push(10).push(20)
s.each { |x| puts x }

Пользовательский порядок обхода

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

class Reversed
  def initialize(arr); @arr = arr; end
  def each
    i = @arr.length - 1
    while i >= 0
      yield @arr[i]
      i -= 1
    end
  end
end
Reversed.new([1, 2, 3]).each { |x| puts x }

Передача нескольких значений

yield может передать несколько значений, которые блок получает как несколько параметров, например ключ и значение хеша.

class Pairs
  def each
    yield :a, 1
    yield :b, 2
  end
end
Pairs.new.each { |key, value| puts "#{key}=#{value}" }

each возвращает self

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

class Box
  def initialize(*x); @x = x; end
  def each
    @x.each { |i| yield i }
    self
  end
end
result = Box.new(1, 2).each { |i| }
puts result.class

Проверка наличия блока

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

class List
  def initialize(*x); @x = x; end
  def each
    return @x.to_enum unless block_given?
    @x.each { |i| yield i }
  end
end
puts List.new(5, 6).each.class

Основа для других методов

После появления each Вы можете создавать на его основе другие методы в том же классе.

class Numbers
  def initialize(*n); @n = n; end
  def each; @n.each { |i| yield i }; end
  def total
    sum = 0
    each { |i| sum += i }
    sum
  end
end
puts Numbers.new(1, 2, 3, 4).total

Вычисляемые последовательности

each не обязан хранить данные: он может создавать значения на лету.

class Evens
  def initialize(limit); @limit = limit; end
  def each
    n = 0
    while n <= @limit
      yield n
      n += 2
    end
  end
end
Evens.new(8).each { |x| puts x }

Основа для Enumerable

Ваш each — единственный строительный блок, необходимый Enumerable. На следующем уроке Вы подключите этот модуль и бесплатно получите десятки методов.

class Range3
  def each
    (1..3).each { |n| yield n }
  end
end
Range3.new.each { |n| print n }
puts

Собираем всё вместе

Пользовательский each даёт полный контроль над итерацией:

  • yield вызывается один раз для каждого элемента.
  • Вы можете обходить элементы в любом порядке, создавать значения или передавать пары.
  • По соглашению возвращайте self.
class Countdown
  def initialize(from); @from = from; end
  def each
    @from.downto(1) { |n| yield n }
  end
end
Countdown.new(3).each { |n| puts n }

Быстрая проверка

Проверьте, насколько хорошо Вы поняли пользовательский each.

Повторение

Вы научились писать собственный each:

  • yield передаёт элементы в блок вызывающего кода.
  • Вы управляете порядком обхода и можете создавать значения.
  • По соглашению возвращайте self.
  • each — основа для Enumerable.
class Squares
  def initialize(n); @n = n; end
  def each
    (1..@n).each { |i| yield i * i }
  end
end
Squares.new(4).each { |sq| puts sq }

Часто задаваемые вопросы

Урок «Написание собственного each» бесплатный?

Да — полный текст урока «Написание собственного each» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Ruby Academy, подпишись на CoddyKit PRO. Курс Ruby Academy содержит 4 уроков всего.

Чему я научусь в уроке «Написание собственного each»?

Реализуйте итерацию Ты практикуешь Ruby Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Ruby Academy?

Предыдущий опыт не требуется. Ruby Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.

Сколько времени занимает урок «Написание собственного each»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Ruby Academy?

Да. Каждый урок Ruby Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Написание собственного each
  2. Подключение Enumerable
  3. Ленивые перечислители
  4. Объекты Enumerator
← Назад к Ruby Academy