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

1803

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

Теги:
conditional
switch-statement

22 ответа

2288
Лучший ответ

Вместо этого 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".

  • 8
    Вы также можете сделать регулярное выражение для переданного аргумента: когда / thisisregex / следующая строка ставит конец: «Это найденное совпадение № 1 # {$ 1}»
  • 0
    Также стоит отметить, что вы можете сократить свой код, поместив операторы when и return в одну строку: when "foo" then "bar"
Показать ещё 1 комментарий
384

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

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

  • 0
    obj = 'привет'; case obj; когда 'привет' тогда ставит конец "Это привет"
193

Это выполняется 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.)

  • 31
    when (-1.0/0.0)..-1 then "Epic fail"
  • 0
    Это ответ, который я использовал, потому что я определяю переменную на основе результатов переключения регистра. Вместо того чтобы произносить type = #{score} каждой строке, я могу просто скопировать то, что вы сделали. Гораздо элегантнее, мне нравятся однострочники гораздо лучше (если это возможно)
89

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

Чтобы добавить дополнительные примеры в 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.

  • 0
    Спасибо, это было полезно для нескольких вариантов на одной строке. Я пытался использовать or
65

В 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 и что вы можете с ним делать.)

64

Многие языки программирования, особенно те, которые производятся от 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', но по большей части я считаю его достаточно похожим, чтобы быть полезным в таким же образом.

51

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

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 (без параметра), только этот подход более чист для этих типов случаев.

31

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

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

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

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

  • 0
    форматирование кода не работает в связанной статье :-)
24

Он называется 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
19

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

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

# 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])
19

Многозначный случай 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
  • 1
    почему бы не просто case some_string, when /\d/, (stuff), when /[a-zA-Z]/, (stuff), end (где , означает новую строку)
  • 1
    о, и первая часть уже покрыта этим ответом , и многие ответы уже упоминают регулярное выражение. Честно говоря, этот ответ не добавляет ничего нового, и я голосую и голосую, чтобы удалить его.
Показать ещё 4 комментария
19

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

puts case a
     when 0
        "It zero"
     when 1
        "It one"
     end
17

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
11

Вы можете записать выражения 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
  • 0
    Хотя ваш код может ответить на этот вопрос, вы должны добавить хотя бы краткое описание того, что делает ваш код и как он решает начальную проблему.
  • 0
    Я рассмотрю этот совет в будущем.
8

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

case expression
when condtion1
   function
when condition2
   function
else
   function
end
8

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

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

  • 6
    Для справки, метод "космический корабль" - это <=> , который используется для возврата -1, 0, 1 или nil в зависимости от того, возвращает ли сравнение меньше, равно, больше или не сопоставимо соответственно , В документации Ruby Comparable module это объясняется.
5
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
4

Как указано во многих из приведенных выше ответов, оператор === используется под капотом на оператора 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. Мы скоро вернемся к этому.

2
$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

1

Мы можем написать оператор 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

Нет поддержки регулярных выражений в вашей среде? Например. 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

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

a = "secondcase"

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

puts var_name
>> "bar"

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

  • 0
    Код, подобный этому, обычно должен выполняться с использованием Hash , а не оператора case .

Ещё вопросы

Сообщество Overcoder
Наверх
Меню