Оператор case в руби

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

case что_то
when значение1
  # если что-то == значение1, идем сюда
when значение2
  # если что-то == значение2, идем сюда
when значение3
  # если что-то == значение3, идем сюда
...
else
  # если никуда выше не зашли, идем сюда
end

# Продолжаем выполнять код

В языках программирования C/C++, C#, Java есть конструкция switch, которая выполняет похожую функцию.

Более жизненный пример. Напишем код, который выводит комментарий по оценке ученика. Сначала с помощью if-elsif-end:

puts "Что получили сегодня за урок?"
mark = gets.to_i

if mark == 2
  puts "Это неуд"
elsif mark == 3
  puts "Удовлетворительно"
elsif mark == 4
  puts "Хорошо"
elsif mark == 5
  puts "Отлично!"
end

Аналогичный код с использованием case будет выглядеть так:

puts "Что получили сегодня за урок?"
mark = gets.to_i

case mark
when 2
  puts "Это неуд"
when 3
  puts "Удовлетворительно"
when 4
  puts "Хорошо"
when 5
  puts "Отлично!"
end

Код становится проще за счет того, что не надо для каждой ветки писать mark ==. Это хорошо.

case и else

В примере выше, если mark не совпадет ни с одним из значений, программа вообще ничего не выведет. Если надо обработать случай, когда в переменной лежит что-то, что не попадает ни под один из случаев, можно написать else после всех when:

puts "Что получили сегодня за урок?"
mark = gets.to_i

case mark
when 2
  puts "Это неуд"
when 3
  puts "Удовлетворительно"
when 4
  puts "Хорошо"
when 5
  puts "Отлично!"
else
  puts "Странная оценка"
end

case и несколько значений через запятую

Представим, что нам не важно, четверка у нас или пятерка. Нам и то и то — «отлично» (как это часто бывает), тогда эти значения можно указать через запятую:

puts "Что получили сегодня за урок?"
mark = gets.to_i

case mark
when 2
  puts "Это неуд"
when 3
  puts "Удовлетворительно"
when 4, 5
  puts "Отлично!"
else
  puts "Странная оценка"
end

Если mark равен 4 или 5, то программа выведет на экран Отлично!. Удобно! За это мы и любим руби.

case c диапазонами (Range)

Вместо одного значения (или нескольких значений через запятую), можно указать диапазон чисел с помощью объекта класса Range, например, (3..5).

puts "Что получили сегодня за урок?"
mark = gets.to_i

case mark
when 2
  puts "Придется пересдавать"
when (3..5)
  puts "Покатит"
else
  puts "Странная оценка"
end

Если mark попадает в диапазон от 3 до 5 (включительно), программа напишет Покатит. Тоже очень удобно.

Короткая запись с then

Если, как в нашем случае, действие для каждого случая умещается в 1 строчку, можно записать это всё короче с помощью ключевого слова then (англ. «тогда»):

puts "Что получили сегодня за урок?"
mark = gets.to_i

case mark
when 2 then puts "Придется пересдавать"
when (3..5) then puts "Покатит"
else
  puts "Странная оценка"
end

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

А что у нас лежит в mark?
Если 2, тогда выведи "Придется пересдавать".
Если от 3 до 5, тогда выведи "Покатит".
Если что-то другое, выведи "Странная оценка".

Обратите внимание, что после else нельзя поставить then и принято писать действие на следующей строчке.

case и сложное выражение

Во всех примерах у нас стоит просто переменная mark. Но после case может быть любое выражение:

case 2 + 2
when 4 then puts "Правильно"
when 5 then puts "Странновато"
end

case без выражения

Формально, в руби можно использовать case даже без выражения:

case
when mark > 0 then puts "Оценка больше нуля"
when mark < 0 then puts "Оценка меньше нуля"
else
  puts "Ну, я даже не знаю"
end

Но такая практика не считается очень удачной. Лучше так не делать.

Когда не надо использовать case?

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

Оператор case лучше всего применять именно когда у вас есть одна переменная (или выражение), которое определяет много принципиально разных сценариев развития программы.

Если же вам просто надо вывести нужную строку в зависимости от числа (как у нас в первом примере), лучше использовать хэш:

mark_names = {
  2 => "Это неуд",
  3 => "Удовлетворительно",
  4 => "Хорошо",
  5 => "Отлично!"
}

puts "Что получили сегодня за урок?"
mark = gets.to_i

puts mark_names[mark]

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

Что «под капотом» у case? *

* — для любознательных

На самом деле в руби case внутри себя вызывает оператор === («триравно», на англ. “threequal”) на указанном после слова when объекте, передавая ему в качестве аргумента указанный после слова case объект. Если интересно, можете прочитать про это в официальной документации.

Пользуйтесь case с умом!

Изучаешь руби?

Заходи в дружелюбный чат, задавай вопросы, делись опытом.

Присоединиться