Spec-Zone.ru › Ruby 2.6

Выражения управления

В 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 только для простых условных выражений. Также избегайте использования нескольких тернарных условий в одном выражении, так как это может быть запутанно.

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 для сравнения String со шаблоном:

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. Триггер изначально выключен (false) для 0 и 1, но включается (true) для 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.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API