Как написать оператор switch в Ruby

Как написать инструкцию switch в Ruby?

1897
04 июня '09 в 4:18
источник поделиться
22 ответов

Вместо этого Ruby использует case выражение.

case x
when 1..5
  "It between 1 and 5"
when 6
  "It 6"
when "foo", "bar"
  "It either foo or bar"
when String
  "You passed a string"
else
  "You gave me #{x} -- I have no idea what to do with that."
end

Ruby сравнивает объект в предложении when с объектом в предложении case с помощью оператора ===. Например, 1..5 === x, а не x === 1..5.

Это позволяет использовать сложные предложения when, как показано выше. Диапазоны, классы и всевозможные вещи можно тестировать, а не просто равенство.

В отличие от операторов switch на многих других языках, Rubys case не имеет fall-through, поэтому нет необходимости заканчивать каждый when с a break. Вы также можете указать несколько совпадений в одном предложении when, таком как when "foo", "bar".

2408
04 июня '09 в 4:22
источник

Связанные вопросы


Похожие вопросы

case...when ведет себя немного неожиданно при обработке классов. Это связано с тем, что он использует оператор ===.

Этот оператор работает так, как ожидалось, с литералами, но не с классами:

1 === 1           # => true
Fixnum === Fixnum # => false

Это означает, что если вы хотите сделать case ... when над классом объекта, это не сработает:

obj = 'hello'
case obj.class
when String
  print('It is a string')
when Fixnum
  print('It is a number')
else
  print('It is not a string')
end

Будет напечатан "Это не строка".

К счастью, это легко решить. Оператор === был определен так, чтобы он возвращал true, если вы используете его с классом, и поставьте экземпляр этого класса в качестве второго операнда:

Fixnum === 1 # => true

Короче говоря, приведенный выше код можно устранить, удалив .class:

obj = 'hello'
case obj  # was case obj.class
when String
  print('It is a string')
when Fixnum
  print('It is a number')
else
  print('It is not a string')
end

Сегодня я столкнулся с этой проблемой, ища ответ, и это была первая появившаяся страница, поэтому я подумал, что это будет полезно для других в моей же ситуации.

404
17 апр. '11 в 18:20
источник

Это выполняется case в Ruby. Также см. эту статью в Википедии.

Цитируется:

case n
when 0
  puts 'You typed zero'
when 1, 9
  puts 'n is a perfect square'
when 2
  puts 'n is a prime number'
  puts 'n is an even number'
when 3, 5, 7
  puts 'n is a prime number'
when 4, 6, 8
  puts 'n is an even number'
else
  puts 'Only single-digit numbers are allowed'
end

Другой пример:

score = 70

result = case score
   when 0..40 then "Fail"
   when 41..60 then "Pass"
   when 61..70 then "Pass with Merit"
   when 71..100 then "Pass with Distinction"
   else "Invalid Score"
end

puts result

На странице 123 (я использую Kindle) в Ruby Programming Lanugage (1st Edition, O'Reilly) говорится, что ключевое слово then, следующее за предложениями when, может быть заменено символом новой строки или точкой с запятой (просто как в синтаксисе if then else). (Ruby 1.8 также позволяет двоеточие вместо then... Но этот синтаксис больше не разрешен в Ruby 1.9.)

193
04 июня '09 в 4:20
источник

случай... когда

Чтобы добавить дополнительные примеры в Chuck answer:

С параметром

case a
when 1
  puts "Single value"
when 2, 3
  puts "One of comma-separated values"
when 4..6
  puts "One of 4, 5, 6"
when 7...9
  puts "One of 7, 8, but not 9"
else
  puts "Any other thing"
end

Без параметра:

case
when b < 3
  puts "Little than 3"
when b == 3
  puts "Equal to 3"
when (1..10) === b
  puts "Something in closed range of [1..10]"
end

Пожалуйста, помните проблему, о которой предупреждает kikito.

89
05 июля '12 в 16:19
источник

Многие языки программирования, особенно те, которые производятся от C, поддерживают так называемый Патч-ход коммутатора. Я искал лучший способ сделать то же самое в Ruby и подумал, что это может быть полезно другим:

В C-подобных языках провал обычно выглядит следующим образом:

switch (expression) {
    case 'a':
    case 'b':
    case 'c':
        // Do something for a, b or c
        break;
    case 'd':
    case 'e':
        // Do something else for d or e
        break;
}

В Ruby это может быть достигнуто следующим образом:

case expression
when 'a', 'b', 'c'
  # Do something for a, b or c
when 'd', 'e'
  # Do something else for d or e
end

Это не является строго эквивалентным, потому что невозможно 'a' выполнить блок кода до перехода на 'b' или 'c', но по большей части я считаю его достаточно похожим, чтобы быть полезным в таким же образом.

67
07 дек. '13 в 15:11
источник

В Ruby 2.0 вы также можете использовать lambdas в операторах case, как показано ниже:

is_even = ->(x) { x % 2 == 0 }

case number
when 0 then puts 'zero'
when is_even then puts 'even'
else puts 'odd'
end

Вы также можете легко создавать свои собственные компараторы, используя Struct с пользовательским ===

Moddable = Struct.new(:n) do
  def ===(numeric)
    numeric % n == 0
  end
end

mod4 = Moddable.new(4)
mod3 = Moddable.new(3)

case number
when mod4 then puts 'multiple of 4'
when mod3 then puts 'multiple of 3'
end

(Пример, взятый из Может ли procs использоваться с операторами case в Ruby 2.0?".)

Или, с полным классом:

class Vehicle
  def ===(another_vehicle)
    self.number_of_wheels == another_vehicle.number_of_wheels
  end
end

four_wheeler = Vehicle.new 4
two_wheeler = Vehicle.new 2

case vehicle
when two_wheeler
  puts 'two wheeler'
when four_wheeler
  puts 'four wheeler'
end

(Пример, взятый из Как работает выражение о работе с Ruby и что вы можете с ним делать.)

65
01 авг. '13 в 3:04
источник

Вы можете использовать регулярные выражения, такие как поиск типа строки:

case foo
when /^(true|false)$/
   puts "Given string is boolean"
when /^[0-9]+$/ 
   puts "Given string is integer"
when /^[0-9\.]+$/
   puts "Given string is float"
else
   puts "Given string is probably string"
end

Ruby case будет использовать операнд равенства === для этого (спасибо @JimDeville). Дополнительную информацию можно найти на Ruby Operators. Это также можно сделать с помощью примера @mmdemirbas (без параметра), только этот подход более чист для этих типов случаев.

49
16 окт. '12 в 15:17
источник

Если вы хотите знать, как использовать условие ИЛИ в случае коммутатора Ruby:

Итак, в выражении case a , является эквивалентом || в выражении if.

case car
   when 'Maruti', 'Hyundai'
      # Code here
end

Многие другие вещи, которые вы можете сделать с утверждением case Ruby

30
03 июля '14 в 9:46
источник

Он называется case, и он работает так, как вы ожидали, плюс много интересного, любезно предоставленного ===, который реализует тесты.

case 5
  when 5
    puts 'yes'
  else
    puts 'else'
end

Теперь для некоторой забавы:

case 5 # every selector below would fire (if first)
  when 3..7    # OK, this is nice
  when 3,4,5,6 # also nice
  when Fixnum  # or
  when Integer # or
  when Numeric # or
  when Comparable # (?!) or
  when Object  # (duhh) or
  when Kernel  # (?!) or
  when BasicObject # (enough already)
    ...
end

И получается, что вы также можете заменить произвольную цепочку if/else (то есть, даже если тесты не включают общую переменную) с case, оставив исходный параметр case и просто записывая выражения где первое совпадение - это то, что вы хотите.

case
  when x.nil?
    ...
  when (x.match /'^fn'/)
    ...
  when (x.include? 'substring')
    ...
  when x.gsub('o', 'z') == 'fnzrq'
    ...
  when Time.now.tuesday?
    ...
end
25
05 февр. '16 в 23:40
источник

В зависимости от вашего случая вы можете предпочесть использовать хэш методов.

Если существует длинный список, когда и каждый из них имеет конкретное значение для сравнения с (а не интервал), будет более эффективным объявлять хэш методов, а затем вызывать соответствующий метод из хеша, например что.

# Define the hash
menu = {a: :menu1, b: :menu2, c: :menu2, d: :menu3}

# Define the methods
def menu1
  puts 'menu 1'
end

def menu2
  puts 'menu 2'
end

def menu3
  puts 'menu3'
end

# Let say we case by selected_menu = :a
selected_menu = :a

# Then just call the relevant method from the hash
send(menu[selected_menu])
20
18 сент. '14 в 17:48
источник

Так как switch case всегда возвращает один объект, мы можем напрямую распечатать его результат:

puts case a
     when 0
        "It zero"
     when 1
        "It one"
     end
19
05 нояб. '13 в 10:29
источник

Многозначный случай if и no-value:

print "Enter your grade: "
grade = gets.chomp
case grade
when "A", "B"
  puts 'You pretty smart!'
when "C", "D"
  puts 'You pretty dumb!!'
else
  puts "You can't even use a computer!"
end

И регулярное выражение:

print "Enter a string: "
some_string = gets.chomp
case
when some_string.match(/\d/)
  puts 'String has numbers'
when some_string.match(/[a-zA-Z]/)
  puts 'String has letters'
else
  puts 'String has no numbers or letters'
end
19
20 янв. '14 в 14:45
источник

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

В соответствии с Ruby Docs:

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

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

Пример:

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

И как этот блог Honeybadger описывает Ruby Case;

Может использоваться с Диапазоны:

case 5
when (1..10)
  puts "case statements match inclusion in a range"
end

## => "case statements match inclusion in a range"

Может использоваться с Regex:

case "FOOBAR"
when /BAR$/
  puts "they can match regular expressions!"
end

## => "they can match regular expressions!"

Может использоваться с Procs и Lambdas:

case 40
when -> (n) { n.to_s == "40" }
  puts "lambdas!"
end

## => "lambdas"

Кроме того, его можно использовать со своими собственными классами совпадений:

class Success
  def self.===(item)
    item.status >= 200 && item.status < 300
  end
end

class Empty
  def self.===(item)
    item.response_size == 0
  end
end

case http_response
when Empty
  puts "response was empty"
when Success
  puts "response was a success"
end
17
18 июля '16 в 22:59
источник

Вы можете записать выражения case двумя способами в ruby.

  • Подобно серии инструкций "if"
  • Укажите цель рядом с корпусом, и каждое предложение "когда" сравнивается с целевым.

1-й способ

age = 20
case 
when age >= 21
puts "display something"
when 1 == 0
puts "omg"
else
puts "default condition"
end

Второй способ

 case params[:unknown]
 when /Something/ then 'Nothing'
 when /Something else/ then 'I dont know'
 end
11
16 февр. '17 в 12:32
источник

Вы можете сделать это более естественным образом,

case expression
when condtion1
   function
when condition2
   function
else
   function
end
8
26 мая '16 в 12:15
источник

Множество отличных ответов, но я думал, что добавлю один факт. Если вы пытаетесь сравнить объекты (классы), убедитесь, что у вас есть метод космического корабля (а не шутка) или понимаете, как они сравниваются

Вот хорошая дискуссия по теме http://www.skorks.com/2009/09/ruby-equality-and-object-comparison/

8
06 авг. '13 в 23:18
источник
puts "Recommend me a language to learn?"
input = gets.chomp.downcase.to_s

case input
when 'ruby'
    puts "Learn Ruby"
when 'python'
    puts "Learn Python"
when 'java'
    puts "Learn Java"
when 'php'
    puts "Learn PHP"
else
    "Go to Sleep!"
end
5
12 марта '16 в 9:33
источник

Как указано во многих из приведенных выше ответов, оператор === используется под капотом на оператора case/when.

Вот несколько дополнительных сведений об этом операторе.

Оператор равенства случая: ===

Многие из встроенных классов Ruby, таких как String, Range и Regexp, предоставляют свои собственные реализации оператора ===, также известные как case-equal, triple equals или threequals. Поскольку он реализован по-разному в каждом классе, он будет вести себя по-разному в зависимости от типа объекта, на который он был вызван. Как правило, он возвращает true, если объект справа "принадлежит" или "является членом" объекта слева. Например, его можно использовать для проверки того, является ли объект экземпляром класса (или одного из его подклассов).

String === "zen"  # Output: => true
Range === (1..2)   # Output: => true
Array === [1,2,3]   # Output: => true
Integer === 2   # Output: => true

Тот же результат может быть достигнут с помощью других методов, которые, вероятно, лучше всего подходят для работы, например is_a? и instance_of?.

Внедрение диапазона ===

Когда оператор === вызывается в объекте диапазона, он возвращает значение true, если значение справа попадает в диапазон слева.

(1..4) === 3  # Output: => true
(1..4) === 2.345 # Output: => true
(1..4) === 6  # Output: => false

("a".."d") === "c" # Output: => true
("a".."d") === "e" # Output: => false

Помните, что оператор === вызывает метод === для левого объекта. Итак, (1..4) === 3 эквивалентно (1..4). === 3. Другими словами, класс левого операнда определит, какая реализация метода === будет так что позиции операнда не взаимозаменяемы.

Регенерация Regexp ===

Возвращает true, если строка справа соответствует регулярному выражению слева.   /zen/ === "Практика дзадзэн сегодня" # Вывод: = > true   # похож на    "практика дзадзэн сегодня" = ~/zen/

Единственное релевантное различие между двумя приведенными выше примерами состоит в том, что когда есть совпадение, === возвращает true и = ~ возвращает целое число, которое является правдивым значением в Ruby. Мы скоро вернемся к этому.

4
06 июля '16 в 19:07
источник
$age =  5
case $age
when 0 .. 2
   puts "baby"
when 3 .. 6
   puts "little child"
when 7 .. 12
   puts "child"
when 13 .. 18
   puts "youth"
else
   puts "adult"
end

reference = > https://www.tutorialspoint.com/ruby/ruby_if_else.htm

2
13 нояб. '17 в 10:58
источник

Нет поддержки регулярных выражений в вашей среде? Например. Shopify Script Редактор (апрель 2018 года):

[Ошибка]: неинициализированная константа RegExp

Обходной путь после комбинации методов, ранее уже описанных в здесь и здесь:

code = '!ADD-SUPER-BONUS!'

class StrContains
  def self.===(item)
    item.include? 'SUPER' or item.include? 'MEGA' or\
    item.include? 'MINI' or item.include? 'UBER'
  end
end

case code.upcase
when '12345PROMO', 'CODE-007', StrContains
  puts "Code #{code} is a discount code!"
when '!ADD-BONUS!'
  puts 'This is a bonus code!'
else
  puts 'Sorry, we can\'t do anything with the code you added...'
end

Я использовал or в инструкции метода класса, поскольку || имеет более высокий приоритет, чем .include?. Если вы ruby-nazi, представьте, что я использовал этот (item.include? 'A') || .... repl.it test.

1
18 апр. '18 в 14:29
источник

Я начал использовать:

a = "secondcase"

var_name = case a
  when "firstcase" then "foo"
  when "secondcase" then "bar"
end

puts var_name
>> "bar"

В некоторых случаях он помогает компактному коду.

1
08 июля '14 в 0:18
источник

Мы можем написать оператор switch для нескольких условий.

Например,

x = 22

CASE x
  WHEN 0..14 THEN puts "#{x} is less than 15"    
  WHEN 15 THEN puts "#{x} equals 15" 
  WHEN 15 THEN puts "#{x} equals 15" 
  WHEN 15..20 THEN puts "#{x} is greater than 15" 
  ELSE puts "Not in the range, value #{x} " 
END
1
25 янв. '19 в 10:32
источник

Посмотрите другие вопросы по меткам или Задайте вопрос