Цикл for в ruby

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

Цикл for относится к конечным циклам, то есть мы заранее знаем условие, при достижении которого цикл прекратит свою работу.

В С++ цикл for используется для создания цикла со счетчиком:

for (int i = 0; i < 5; i++) {
 cout << i << endl;
}

Цикл for в Python:

for number in [0, 1, 2, 3, 4]:
    print(number)

Цикл for в JavaScript:

let step;

for (step = 0; step < 5; step++) {
  console.log(step);
}

Цикл for в ruby

В руби оператор for тоже есть. Синтаксис у него очень простой и чем-то похожий на питон:

for <элемент> in <массив> [do]
  <действие>
end

Такой цикл выполняет <действие> один раз для каждого <элемента> в <массиве>. Ключевое слово [do] 一 здесь можно (и нужно) опустить.

Цикл for и массив строк

Допустим, мы хотим вывести все футбольные команды из такого массива:

["ЦСКА", "Зенит", "Динамо", "Спартак"]

С помощью for это можно сделать так:

teams = ["ЦСКА", "Зенит", "Динамо", "Спартак"]

for team in teams
  puts team
end

Такой код выведет:

ЦСКА
Зенит
Динамо
Спартак

Цикл for и массив чисел

Конечно, в массиве могут быть любые объекты, не только строки. Например, выведем степени числа 2 с помощью for и массива чисел:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

for i in numbers do
  puts 2**i
end

При выводе будет:

2
4
8
16
32
64
128
256
512
1024

Цикл for и диапазон (Range)

С помощью for в руби можно обойти не только массив, но и, например, диапазон (объект класса Range). Перепишем наш пример про степени двойки:

for i in (1..10)
  puts 2**i
end

Результат будет такой же:

2
4
8
16
32
64
128
256
512
1024

Цикл с each

В руби вместо цикла for для диапазонов (и массивов) принято использовать метод each. Делает он абсолютно то же самое, но записывается немного иначе.

Пример со степенями числа 2 перепишем через each:

(1..10).each do |i|
  puts 2**i
end

Или даже короче, в одну строчку:

(1..10).each { |i| puts 2**i }

Вывод (в обоих случаях):

2
4
8
16
32
64
128
256
512
1024

Итератор each перебирает элементы диапазона (1..10), и передает элемент i в блок, где каждый i используется в качестве степени двойки (для оператора **), которую мы потом выводим на экран методом puts.

На русский язык этот код, записанный на ruby, можно перевести как-то так: «возьми каждый элемент из диапазона (1..10), возведи число 2 в эту степень и выведи на экран».

Выглядит более наглядно и емко. При чтении кода сразу видно, что происходит. Без лишних слов, как в случае с for. Поэтому в руби предпочитают использовать each.

Области видимости в for и в each

Различие между циклами с for и с each — в областях видимости.

Любая переменная, которую вы объявляете в цикле for, будет доступна вне цикла, переменные в блоке итератора each — доступны только внутри этого блока.

arr = [1, 2, 3]

for element in array do
  puts element
end

# element доступен за пределами цикла

element #=> 3

array.each { |element| puts elements }

# element недоступен за пределами блока `each`

element #=> NameError: undefined local variable or method `element`

Какие диапазоны можно перебрать с помощью each?

Вы можете осуществить перебор диапазона (как в цикле с each, так и в цикле с for) только в том случае, если все элементы диапазона поддерживают метод succ (следующий).

('*'..'+').each { |x| puts "#{x} -> #{x.succ}" }

puts

('d'..'f').each { |x| puts "#{x} -> #{x.succ}" }

Выведет:

* -> +
+ -> ,

d -> e
e -> f
f -> g

Перебор элементов из интервала, состоящего из экземпляров класса Float невозможен.

(0.1..0.4).each { |x| puts x }

#=> in `each`: can't iterate from Float (TypeError)

Что «под капотом» у for? *

* — для любознательных

На самом деле, внутри оператора for используется всё тот же each. Об этом написано, например, в документации:

The for loop consists of for followed by a variable to contain the iteration argument followed by in and the value to iterate over using each.

Также можно почитать об этом здесь. Автор считает, что for был сделан в руби только для того, чтобы разработчикам, которые пришли в руби из других языков, было комфортнее.

Опытные разработчики в руби не пользуются for. Используйте вместо него each.

Изучаешь руби?

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

Присоединиться