Выражения управления
В Ruby есть множество способов управления выполнением. Все описанные здесь выражения возвращают значение.
Для тестов в этих выражениях управления nil и false являются ложными значениями, а true и любой другой объект — истинными значениями. В этом документе «истина» означает «истинное значение», а «ложь» — «ложное значение».
if выражение
Самое простое if выражение состоит из двух частей: выражения «проверки» и выражения «тогда». Если выражение «проверки» вычисляет истинное значение, то вычисляется выражение «тогда».
Вот простой оператор if:
if true then puts "the test resulted in a true-value" end
Это выведет «тест дал истинное значение».
then является необязательным:
if true puts "the test resulted in a true-value" end
В этом документе необязательное then будет опущено для всех выражений, так как это наиболее распространённое использование if.
Вы также можете добавить выражение else. Если тест не вычисляет истинное значение, то будет выполнено выражение else:
if false puts "the test resulted in a true-value" else puts "the test resulted in a false-value" end
Это выведет «тест дал ложное значение».
Вы можете добавить любое количество дополнительных проверок в выражение if, используя elsif. Выражение elsif выполняется, когда все проверки выше elsif являются ложными.
a = 1 if a == 0 puts "a is zero" elsif a == 1 puts "a is one" else puts "a is some other value" end
Это выведет «a равно единице», так как 1 не равно 0. Поскольку else выполняется только тогда, когда нет совпадающих условий.
Как только условие совпадает, либо с if условием, либо с любым elsif условием, выражение if завершается, и дальнейшие проверки не будут выполняться.
Так же как и в if, за условием elsif может следовать then.
В этом примере выводится только «a равно единице»:
a = 1 if a == 0 puts "a is zero" elsif a == 1 puts "a is one" elsif a >= 1 puts "a is greater than or equal to one" else puts "a is some other value" end
Проверки для if и elsif могут иметь побочные эффекты. Наиболее распространённое использование побочных эффектов — кеширование значения в локальной переменной:
if a = object.some_value # do something to a end
Значение результата выражения if — это последнее значение, выполненное в выражении.
Тernary if
Вы также можете записать выражение if-then-else, используя ? и :. Этот условный оператор if:
input_type = gets =~ /hello/i ? "greeting" : "other"
Эквивалентен этому выражению if:
input_type =
if gets =~ /hello/i
"greeting"
else
"other"
end
Хотя условный оператор if короче, чем более подробный вариант, для повышения читабельности рекомендуется использовать условный оператор if только для простых условных выражений. Также избегайте использования нескольких условных операторов if в одном выражении, так как это может привести к путанице.
unless выражение
Выражение unless — это противоположность выражению if выражению. Если значение ложное, то выполняется выражение «тогда»:
unless true puts "the value is a false-value" end
Это не выводит ничего, так как true не является ложным значением.
Вы можете использовать необязательное then с unless так же, как и if.
Обратите внимание, что вышеприведённое выражение unless эквивалентно:
if not true puts "the value is a false-value" end
Так же, как и в выражении if, вы можете использовать условие else с unless:
unless true puts "the value is false" else puts "the value is true" end
Это выводит «значение истинно» из условия else.
Вы не можете использовать elsif с выражением unless.
Значение результата выражения unless — это последнее значение, выполненное в выражении.
Модификатор if и unless
if и unless также могут использоваться для модификации выражения. При использовании в качестве модификатора левая часть — это выражение «тогда», а правая часть — выражение «проверки»:
a = 0 a += 1 if a.zero? p a
Это выведет 1.
a = 0 a += 1 unless a.zero? p a
Это выведет 0.
Хотя у модифицированного и стандартного вариантов есть выражение «проверки» и выражение «тогда», они не являются точными преобразованиями друг друга из-за порядка разбора. Вот пример, который показывает разницу:
p a if a = 0.zero?
Это вызывает NameError «неопределённая локальная переменная или метод `a'».
Когда Ruby парсит это выражение, он сначала встречает a как вызов метода в выражении «тогда», а затем позже видит присвоение a в выражении «проверки» и отмечает a как локальную переменную.
При выполнении этой строки сначала выполняется выражение «проверки», a =
0.zero?.
Поскольку проверка истинна, выполняется выражение «тогда», p a. Поскольку a в теле было записано как метод, которого не существует, возникает NameError.
То же самое относится и к unless.
case выражение
Выражение case может использоваться двумя способами.
Наиболее распространённый способ — сравнить объект с несколькими шаблонами. Шаблоны сопоставляются с помощью метода +===+, который является псевдонимом для +==+ в классе Object. Другие классы должны переопределять его, чтобы обеспечить осмысленное поведение. См. Module#=== и Regexp#=== для примеров.
Вот пример использования case для сравнения строки с шаблоном:
case "12345" when /^1/ puts "the string starts with one" else puts "I don't know what the string starts with" end
Здесь строка "12345" сравнивается с /^1/ путём вызова /^1/ === "12345", который возвращает true. Как и в выражении if , первое when , которое совпадает, выполняется, а все остальные совпадения игнорируются.
Если совпадений не найдено, выполняется else.
else и then являются необязательными, это выражение case даёт тот же результат, что и вышеприведённое:
case "12345" when /^1/ puts "the string starts with one" end
Вы можете поместить несколько условий в одно и то же when:
case "2" when /^1/, "2" puts "the string starts with one or is '2'" end
Ruby будет пытаться выполнить каждое условие по очереди, поэтому сначала /^1/ ===
"2" возвращает false, а затем "2"
=== "2" возвращает true, поэтому выводится «строка начинается с единицы или равна "2"».
Вы можете использовать then после условия when . Это чаще всего используется для размещения тела when в одной строке.
case a when 1, 2 then puts "a is one or two when 3 then puts "a is three" else puts "I don't know what a is" end
Другой способ использования выражения case — это как выражение if-elsif:
a = 2 case when a == 1, a == 2 puts "a is one or two" when a == 3 puts "a is three" else puts "I don't know what a is" end
Опять же, then и else являются необязательными.
Значение результата выражения case — это последнее значение, выполненное в выражении.
while цикл
Цикл while выполняется, пока условие истинно:
a = 0 while a < 10 do p a a += 1 end p a
Выводит числа от 0 до 10. Условие a < 10 проверяется до входа в цикл, затем выполняется тело, затем условие проверяется снова. Когда условие становится ложным, цикл завершается.
Ключевое слово do необязательно. Следующий цикл эквивалентен вышеприведённому:
while a < 10 p a a += 1 end
Результат цикла while — это nil, если не используется break для задания значения.
until цикл
Цикл until выполняется, пока условие ложно:
a = 0 until a > 10 do p a a += 1 end p a
Это выводит числа от 0 до 11. Как и в цикле while, условие a > 10 проверяется при входе в цикл и каждый раз при выполнении тела цикла. Если условие ложно, цикл продолжает выполняться.
Как и в цикле while, do является необязательным.
Как и в цикле while, результат цикла until равен nil, если не используется break.
for цикл
Цикл for состоит из for, за которым следует переменная для хранения аргумента итерации, за которым следует in и значение для итерации с помощью each. do является необязательным:
for value in [1, 2, 3] do puts value end
Выводит 1, 2 и 3.
Как и в циклах while и until, do является необязательным.
Цикл for похож на использование each, но не создаёт новую область видимости переменных.
Результат цикла for — это итерируемое значение, если не используется break.
Цикл for редко используется в современных программах Ruby.
Модификатор while и until
Как и в if и unless, while и until могут использоваться в качестве модификаторов:
a = 0 a += 1 while a < 10 p a # prints 10
until в качестве модификатора:
a = 0 a += 1 until a > 10 p a # prints 11
Вы можете использовать begin и end для создания цикла while , который выполняет тело один раз до проверки:
a = 0 begin a += 1 end while a < 10 p a # prints 10
Если вы не используете rescue или ensure, Ruby оптимизирует любые накладные расходы на обработку исключений.
break оператор
Используйте break для преждевременного выхода из блока. Это остановит итерацию по элементам в values, если один из них чётный:
values.each do |value| break if value.even? # ... end
Вы также можете завершить цикл while с помощью break:
a = 0 while true do p a a += 1 break if a < 10 end p a
Это выводит числа 0 и 1.
break принимает значение, которое задаёт результат выражения, из которого происходит «выход»:
result = [1, 2, 3].each do |value| break value * 2 if value.even? end p result # prints 4
next оператор
Используйте next для пропуска остальной части текущей итерации:
result = [1, 2, 3].map do |value| next if value.even? value * 2 end p result # prints [2, nil, 6]
next принимает аргумент, который можно использовать как результат текущей итерации блока:
result = [1, 2, 3].map do |value| next value if value.even? value * 2 end p result # prints [2, 2, 6]
redo оператор
Используйте redo для повторения текущей итерации:
result = [] while result.length < 10 do result << result.length redo if result.last.even? result << result.length + 1 end p result
Это выводит [0, 1, 3, 3, 5, 5, 7, 7, 9, 9, 11]
В Ruby 1.8 вы также могли использовать retry вместо redo. Это больше не так, сейчас вы получите SyntaxError, если используете retry вне блока rescue. См. Исключения для правильного использования retry.
Переключатель
Триггер — это редко используемое условное выражение. Его основное применение — обработка текста из однострочных программ Ruby, используемых с ruby
-n или ruby -p.
Формат триггера — это выражение, указывающее, когда триггер включается, .. (или ...), а затем выражение, указывающее, когда триггер выключится. Пока триггер включен, он будет продолжать возвращать значение true, а false — когда выключен.
Вот пример:
selected = [] 0.upto 10 do |value| selected << value if value==2..value==8 end p selected # prints [2, 3, 4, 5, 6, 7, 8]
В приведенном выше примере условие включения — n==2. Триггер изначально выключен (ложь) для 0 и 1, но включается (истина) для 2 и остается включенным до 8. После 8 он выключается и остается выключенным для 9 и 10.
Триггер необходимо использовать внутри условного оператора, такого как if, while, unless, until и т. д., включая модифицированные формы.
При использовании инклюзивного диапазона (..) условие выключения вычисляется при изменении условия включения:
selected = [] 0.upto 5 do |value| selected << value if value==2..value==2 end p selected # prints [2]
Здесь обе стороны триггера вычисляются, поэтому триггер включается и выключается только тогда, когда value равно 2. Поскольку триггер включился в итерации, он возвращает true.
При использовании эксклюзивного диапазона (...) условие выключения оценивается на следующей итерации:
selected = [] 0.upto 5 do |value| selected << value if value==2...value==2 end p selected # prints [2, 3, 4, 5]
Здесь триггер включается, когда value равно 2, но не выключается в той же итерации. Условие выключения оценивается только на следующей итерации, и value никогда не будет равно двум.
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.