Поиск…


if, elsif, else и end

Ruby предлагает ожидаемые выражения if и else для логики ветвления, завершенные ключевым словом end :

# Simulate flipping a coin
result = [:heads, :tails].sample

if result == :heads
  puts 'The coin-toss came up "heads"'
else
  puts 'The coin-toss came up "tails"'
end

В Ruby, if операторы являются выражениями, которые оценивают значение, и результат может быть назначен переменной:

status = if age < 18
           :minor
         else
           :adult
         end

Ruby также предлагает тройные операторы C-стиля ( подробнее см. Здесь ), которые могут быть выражены как:

some_statement ? if_true : if_false  

Это означает, что приведенный выше пример с использованием if-else также может быть записан как

status = age < 18 ? :minor : :adult

Кроме того, Ruby предлагает ключевое слово elsif которое принимает выражение для включения дополнительной логики ветвления:

label = if shirt_size == :s
          'small'
        elsif shirt_size == :m
          'medium'
        elsif shirt_size == :l
          'large'
        else
          'unknown size'
        end

Если ни одно из условий в цепочке if / elsif является истинным, и нет предложения else , тогда выражение оценивается как nil. Это может быть полезно внутри интерполяции строк, поскольку nil.to_s - это пустая строка:

"user#{'s' if @users.size != 1}"

Значения Truthy и Falsy

В Ruby существует ровно два значения, которые считаются «ложными» и будут возвращать false при проверке как условие для выражения if . Они есть:

  • nil
  • boolean false

Все остальные значения считаются «правдивыми», в том числе:

  • 0 - числовой ноль (целое или иное)
  • "" - Пустые строки
  • "\n" - Строки, содержащие только пробелы
  • [] - пустые массивы
  • {} - Пустые хеши

Возьмем, к примеру, следующий код:

def check_truthy(var_name, var)
  is_truthy = var ? "truthy" : "falsy"
  puts "#{var_name} is #{is_truthy}"
end

check_truthy("false", false)
check_truthy("nil", nil)
check_truthy("0", 0)
check_truthy("empty string", "")
check_truthy("\\n", "\n")
check_truthy("empty array", [])
check_truthy("empty hash", {})

Вывод:

false is falsy
nil is falsy
0 is truthy
empty string is truthy
\n is truthy
empty array is truthy
empty hash is truthy

пока, пока

В while цикл выполняется блок , пока данное условие:

i = 0
while i < 5
  puts "Iteration ##{i}"
  i +=1
end

until цикл не выполнит блок, а условие - false:

i = 0
until i == 5
  puts "Iteration ##{i}"
  i +=1
end

Встроенный if / if

Общим примером является использование встроенного или конечного, if или unless :

puts "x is less than 5" if x < 5

Это называется условным модификатором и является удобным способом добавления простого защитного кода и ранних возвратов:

def save_to_file(data, filename)
  raise "no filename given" if filename.empty?
  return false unless data.valid?

  File.write(filename, data)
end

К этим модификаторам нельзя добавить предложение else . Также обычно не рекомендуется использовать условные модификаторы внутри основной логики. Для сложного кода следует использовать нормальный if , elsif , else вместо.

если

Общим утверждением является if !(some condition) . Рубин предлагает альтернативу в unless , unless заявление.

Структура точно такая же, как и оператор if , за исключением того, что условие отрицательное. Кроме того , unless оператор не поддерживает elsif , но он поддерживает else :

# Prints not inclusive
unless 'hellow'.include?('all')
  puts 'not inclusive'
end

Заявление о ситуации

Ruby использует ключевое слово case для операторов switch.

Согласно Ruby Docs :

Операторы case состоят из необязательного условия, которое находится в позиции аргумента к case , и ноль или более when клаузе. Параметр first when , чтобы соответствовать условию (или для оценки логической истины, если условие равно null) «выигрывает», и выполняется его строфа кода. Значение аргумента case - это значение успешного предложения when , или nil если такого предложения нет.

Оператор case может закончиться предложением else . Каждый, when оператор может иметь несколько значений кандидата, разделенных запятыми.

Пример:

case x
when 1,2,3
  puts "1, 2, or 3"
when 10
  puts "10"
else
  puts "Some other number"
end

Более короткая версия:

case x
when 1,2,3 then puts "1, 2, or 3"
when 10 then puts "10"
else puts "Some other number"
end

Значение case п сравниваются с каждым , when положение с использованием === методы (не == ). Поэтому его можно использовать с различными типами объектов.

Оператор case может использоваться с диапазонами :

case 17
when 13..19
  puts "teenager"
end

Оператор case может использоваться с Regexp :

case "google"
when /oo/
  puts "word contains oo"
end

Оператор case может использоваться с Proc или лямбдой:

case 44
when -> (n) { n.even? or n < 0 }
  puts "even or less than zero"
end

Оператор case может использоваться с классами :

case x
when Integer
  puts "It's an integer"
when String
  puts "It's a string"
end

Внедряя метод === вы можете создавать свои собственные классы соответствия:

class Empty
  def self.===(object)
    !object or "" == object
  end
end

case ""
when Empty
  puts "name was empty"
else
  puts "name is not empty"
end

Оператор case может использоваться без значения для соответствия:

case
when ENV['A'] == 'Y'
  puts 'A'
when ENV['B'] == 'Y'
  puts 'B'
else
  puts 'Neither A nor B'
end

Оператор case имеет значение, поэтому вы можете использовать его как аргумент метода или в задании:

description = case 16
              when 13..19 then "teenager"
              else ""
              end

Управление контуром с перерывом, затем и повтор

Поток выполнения блока Ruby может контролироваться с помощью break , next и redo операторов.

break

Оператор break немедленно выйдет из блока. Любые оставшиеся инструкции в блоке будут пропущены, и итерация закончится:

actions = %w(run jump swim exit macarena)
index = 0

while index < actions.length
  action = actions[index]

  break if action == "exit"

  index += 1
  puts "Currently doing this action: #{action}"
end

# Currently doing this action: run
# Currently doing this action: jump
# Currently doing this action: swim

next

next оператор немедленно вернется в верхнюю часть блока и продолжит следующую итерацию. Любые оставшиеся команды в блоке будут пропущены:

actions = %w(run jump swim rest macarena)
index = 0

while index < actions.length
  action = actions[index]
  index += 1

  next if action == "rest"

  puts "Currently doing this action: #{action}"
end

# Currently doing this action: run
# Currently doing this action: jump
# Currently doing this action: swim
# Currently doing this action: macarena

redo

Оператор redo немедленно вернется в начало блока и повторит ту же самую итерацию. Любые оставшиеся команды в блоке будут пропущены:

actions = %w(run jump swim sleep macarena)
index = 0
repeat_count = 0

while index < actions.length
  action = actions[index]
  puts "Currently doing this action: #{action}"

  if action == "sleep"
    repeat_count += 1
    redo if repeat_count < 3
  end

  index += 1
end

# Currently doing this action: run
# Currently doing this action: jump
# Currently doing this action: swim
# Currently doing this action: sleep
# Currently doing this action: sleep
# Currently doing this action: sleep
# Currently doing this action: macarena

Enumerable итерация

В дополнение к циклам эти операторы работают с методами перечислимого итерации, такими как each и map :

[1, 2, 3].each do |item|
  next if item.even?
  puts "Item: #{item}"
end

# Item: 1
# Item: 3

Заблокировать значения результата

В обоих break и next значение может быть предоставлено и будет использоваться как значение результата блока:

even_value = for value in [1, 2, 3]
  break value if value.even?
end

puts "The first even value is: #{even_value}"

# The first even value is: 2

бросать, ловить

В отличие от многих других языков программирования ключевые слова throw and catch не связаны с обработкой исключений в Ruby.

В Ruby, throw и catch действуют как ярлыки на других языках. Они используются для изменения потока управления, но не связаны с понятием «ошибка», например «Исключения».

catch(:out) do
  catch(:nested) do
    puts "nested"
  end

  puts "before"
  throw :out
  puts "will not be executed"
end
puts "after"
# prints "nested", "before", "after"

Управляющий поток с логическими инструкциями

Хотя это может показаться нелогичным, вы можете использовать логические операторы для определения того, выполняется ли оператор. Например:

File.exist?(filename) or STDERR.puts "#{filename} does not exist!"

Это проверит, существует ли файл, и только распечатывает сообщение об ошибке, если это не так. Оператор or является ленивым, что означает, что он перестанет выполняться, если он уверен, что значение true или false. Как только первый термин окажется истинным, нет необходимости проверять значение другого термина. Но если первый член является ложным, он должен проверить второй член.

Обычно используется значение по умолчанию:

glass = glass or 'full' # Optimist! 

Это устанавливает значение «full» для glass если оно еще не установлено. Более кратко, вы можете использовать символическую версию or :

glass ||= 'empty' # Pessimist. 

Также можно запустить второй оператор только в том случае, если первый из них является ложным:

File.exist?(filename) and puts "#{filename} found!"

Опять же, and ленив, поэтому он будет выполнять только второй оператор, если необходимо, чтобы получить значение.

Оператор or имеет более низкий приоритет, чем and . Аналогично, || имеет более низкий приоритет, чем && . Формы символов имеют более высокий приоритет, чем словоформы. Это удобно знать, когда вы хотите смешать эту технику с назначением:

a = 1 and b = 2
#=> a==1
#=> b==2
a = 1 && b = 2; puts a, b
#=> a==2
#=> b==2

Обратите внимание, что руководство по стилю Ruby рекомендует :

Запрещены and и / or ключевые слова. Минимальная добавленная читаемость просто не стоит высокой вероятности введения тонких ошибок. Для булевых выражений всегда используйте && и || вместо. Для управления потоком используйте, if и unless ; && и || также приемлемы, но менее ясны.

начинать, заканчивать

begin блок - это структура управления, объединяющая несколько операторов.

begin
  a = 7
  b = 6
  a * b
end

begin блок вернет значение последнего оператора в блоке. Следующий пример вернет 3 .

begin
  1
  2
  3
end

begin блок полезен для условного присваивания с помощью оператора ||= где для возврата результата может потребоваться несколько операторов.

circumference ||=
  begin
    radius = 7
    tau = Math::PI * 2
    tau * radius
  end

Он также может быть объединен с другими блочными структурами, такими как rescue , ensure , while if , unless , и т. Д., Чтобы обеспечить больший контроль над потоком программы.

Begin блоки не кодовые блоки, например { ... } или do ... end ; они не могут быть переданы в функции.

return vs. next: нелокальное возвращение в блок

Рассмотрим этот сломанный фрагмент:

def foo
  bar = [1, 2, 3, 4].map do |x|
    return 0 if x.even?
    x
  end
  puts 'baz'
  bar
end
foo # => 0

Можно было бы ожидать return , чтобы получить значение для map массива «s результатов блока. Таким образом, возвращаемое значение foo будет [1, 0, 3, 0] . Вместо этого return возвращает значение из метода foo . Обратите внимание, что baz не печатается, что означает, что выполнение никогда не достигало этой строки.

next со значением делает трюк. Он действует как return уровне блока.

def foo
  bar = [1, 2, 3, 4].map do |x|
    next 0 if x.even?
    x
  end
  puts 'baz'
  bar
end
foo # baz
    # => [1, 0, 3, 0]

В отсутствие return значение, возвращаемое блоком, является значением его последнего выражения.

Оператор Or-Equals / Conditional присваивания (|| =)

Ruby имеет оператор or-equals, который позволяет присваивать значение переменной тогда и только тогда, когда эта переменная оценивается как nil и false .

 ||= # this is the operator that achieves this. 

этот оператор с двойными трубами, представляющими знак или знак равенства, представляющий присвоение значения. Вы можете подумать, что это что-то вроде этого:

 x = x || y

этот вышеприведенный пример неверен. Оператор or-equals фактически представляет это:

 x || x = y

Если x вычисляет значение nil или false то x присваивается значение y и в противном случае остается неизменным.

Вот практический пример использования оператора or-equals. Представьте, что у вас есть часть вашего кода, которая, как ожидается, отправит электронное письмо пользователю. Что вы делаете, если по какой-либо причине нет электронной почты для этого пользователя. Вы могли бы написать что-то вроде этого:

 if user_email.nil?
    user_email = "[email protected]"
 end

Используя оператор or-equals, мы можем разрезать весь этот фрагмент кода, обеспечивая чистый, четкий контроль и функциональность.

 user_email ||= "[email protected]"

В случаях, когда false является допустимым значением, необходимо соблюдать осторожность, чтобы не переопределять его случайно:

has_been_run = false
has_been_run ||= true
#=> true

has_been_run = false
has_been_run = true if has_been_run.nil?
#=> false

Тернарный оператор

Ruby имеет тернарный оператор ( ?: :), Который возвращает одно из двух значений, основанное на том, что условие оценивается как правдивое:

conditional ? value_if_truthy : value_if_falsy

value = true
value ? "true" : "false"
#=> "true"

value = false
value ? "true" : "false"
#=> "false"

это то же самое, что и запись, if a then b else c end , хотя предпочтительна тройка

Примеры:

puts (if 1 then 2 else 3 end) # => 2

puts 1 ? 2 : 3                # => 2

x = if 1 then 2 else 3 end
puts x                        # => 2

Флип-флоп-оператор

Оператор flip flop .. используется между двумя условиями в условном выражении:

(1..5).select do |e|
  e if (e == 2) .. (e == 4)
end
# => [2, 3, 4]

Условие оценивается как false пока первая часть не станет true . Затем он оценивает значение true пока вторая часть не станет true . После этого он снова переключится на значение false .

Этот пример иллюстрирует, что выбирается:

[1, 2, 2, 3, 4, 4, 5].select do |e|
  e if (e == 2) .. (e == 4)
end
# => [2, 2, 3, 4]

Оператор триггера работает только внутри ifs (включая unless ) и тройного оператора. В противном случае он рассматривается как оператор диапазона.

(1..5).select do |e|
  (e == 2) .. (e == 4)
end
# => ArgumentError: bad value for range

Он может переключаться с false на true и обратные несколько раз:

((1..5).to_a * 2).select do |e|
  e if (e == 2) .. (e == 4)
end
# => [2, 3, 4, 2, 3, 4] 


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow