when 'другое значение'
puts 'Ветвь 2'
when /симв/
puts 'Ветвь 3'
else
puts 'Ветвь 4'
end
Этот код напечатает Ветвь 3
. Почему? Сначала проверяемое выражение сравнивается на равенство с двумя строками: 'одно значение'
и 'другое значение'
. Эта проверка завершается неудачно, поэтому мы переходим к третьей ветви. Там находится образец, с которым сопоставляется выражение. Поскольку оно соответствует образцу, то выполняется предложение print
. В ветви else
обрабатывается случай, когда ни одна из предшествующих проверок не прошла.
Если проверяемое выражение — целое число, то его можно сравнивать с целочисленным диапазоном (например, 3..8
); тогда проверяется, что число попадает в диапазон. В любом случае выполняется код в первой подошедшей ветви.
В Ruby имеется богатый набор циклических конструкций. К примеру, while
и until
— циклы с предварительной проверкой условия, и оба работают привычным образом: в первом случае задается условие продолжения цикла, а во втором — условие завершения. Есть также их формы с модификатором, как для предложений if
и unless
. Кроме того, в модуле Kernel
есть метод loop
(по умолчанию бесконечный цикл), а в некоторых классах реализованы итераторы.
В примерах из таблицы 1.2 предполагается, что где-то определен такой массив list
:
list = %w[alpha bravo charlie delta echo];
В цикле этот массив обходится и печатается каждый его элемент.
Таблица 1.2. Циклы
# Цикл 1 (while) | # Цикл 2 (until) |
---|---|
i=0 while i < list.size do print '#{list[i]} ' i += 1 end | i=0 until i == list.size do print '#{list[i]} ' i += 1 end |
# Цикл 3 (for) | # Цикл 4 (итератор 'each') |
for x in list do print '#{x} ' end | list.each do |x| print '#{x} ' end |
# Цикл 5 (метод 'loop') | # Цикл 6 (метод 'loop') |
i = 0 n=list.size-1 loop do print '#{list[i]} ' i += 1 break if i > n end | i=0 n=list.size-1 loop do print '#{list[i]} ' i += 1 break unless i <= n end |
# Цикл 7 (итератор 'times') | # Цикл 8 (итератор 'upto') |
n=list.size n.times do |i| print '#{list[i]} ' end | n=list.size-1 0.upto(n) do |i| print '#{list[i]} ' end |
# Цикл 9 (for) | # Цикл 10 ('each_index') |
n=list.size-1 for i in 0..n do print '#{list[i]} ' end | list.each_index do |x| print '#{list[x]} ' end |
Рассмотрим эти примеры более подробно. Циклы 1 и 2 — «стандартные» формы циклов while
и until
; ведут они себя практически одинаково, только условия противоположны. Циклы 3 и 4 — варианты предыдущих с проверкой условия в конце, а не в начале итерации. Отметим, что использование слов begin
и end
в этом контексте — просто грязный трюк; на самом деле это был бы блок begin/end (применяемый для обработки исключений), за которым следует модификатор while
или until
. Однако для тех, кто желает написать цикл с проверкой в конце, разницы нет.
На мой взгляд, конструкции 3 и 4 — самый «правильный» способ кодирования циклов. Они заметно проще всех остальных: нет ни явной инициализации, ни явной проверки или инкремента. Это возможно потому, что массив «знает» свой размер, а стандартный итератор each
(цикл 6) обрабатывает такие детали автоматически. На самом деле в цикле 5 производится неявное обращение к этому итератору, поскольку цикл for
работает с любым объектом, для которого определен итератор each
. Цикл for
— лишь сокращенная запись для вызова each
; часто такие сокращения называют «синтаксической глазурью», имея в виду, что это не более чем удобная альтернативная форма другой синтаксической конструкции.
В циклах 5 и 6 используется конструкция loop
. Выше мы уже отмечали, что хотя loop
выглядит как ключевое слово, на самом деле это метод модуля Kernel
, а вовсе не управляющая конструкция.
В циклах 7 и 8 используется тот факт, что у массива есть числовой индекс. Итератор times
исполняется заданное число раз, а итератор upto
увеличивает свой параметр до заданного значения. И тот, и другой для данной ситуации приспособлены плохо.
Цикл 9 — это вариант цикла for
, предназначенный специально для работы со значениями индекса при помощи указания диапазона. В цикле 10 мы пробегаем весь диапазон индексов массива с помощью итератора each_index
.
В предыдущих примерах мы уделили недостаточно внимания вариантам циклов while
и loop
с модификаторами. Они довольно часто используются из-за краткости. Вот еще два примера, в которых делается одно и то же: