Spec-Zone.ru › Ruby 2.4

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

В 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. Триггер изначально выключен (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