Spec-Zone.ru › Ruby 2.3

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

В 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 — это последнее выполненное значение в выражении.

Условное выражение 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