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

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

21 ответов


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

case x
when 1..5
  "It's between 1 and 5"
when 6
  "It's 6"
when "foo", "bar"
  "It's 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 заявления на многих других языках, Руби!--1--> нет падение-через, так что нет необходимости заканчивать каждый when С break. Вы также можете указать несколько совпадений в одном when предложение like when "foo", "bar".


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

напечатает "это не строка".

к счастью, это легко решается. The === оператор был определен так что он возвращается 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

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


это делают случае в Руби. Также смотрите эта статья в Википедии.

цитировать:

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) из Рубиновое Программирование Lanugage (1-е издание, О'Рейли), там написано then сайта после when предложения могут быть заменены новой строкой или точкой с запятой (как и в if then else синтаксис). (Ruby 1.8 также позволяет двоеточие на месте из then... Но этот синтаксис больше не разрешен в Ruby 1.9.)


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

чтобы добавить больше примеров в Чак:

параметр:

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 предупреждает.


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

в C-подобных языках fallthrough обычно выглядит так:

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


в 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

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

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 Case И Что Вы Можете Сделать С Это".)


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

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

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


если вы хотите знать, как использовать условие OR в случае рубинового переключателя:

так, в case заявление, a , эквивалентно || на if заявление.

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

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


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

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

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

# 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's say we case by selected_menu = :a
selected_menu = :a

# Then just call the relevant method from the hash
send(menu[selected_menu])

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

puts case a
     when 0
        "It's zero"
     when 1
        "It's one"
     end

Multi-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

Ruby использует case для написания инструкций.

на Ruby Docs:

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

заявление по делу может заканчиваться на 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 5
when (1..10)
  puts "case statements match inclusion in a range"
end

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

можно использовать с выражение:

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

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

можно использовать с Прокс и лямбда:

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

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

  1. похоже на серию утверждений "if"
  2. укажите цель рядом с регистром и каждое предложение" when " сравнивается с целью.

1-й способ

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

2-й способ

 case params[:unknown]
 when /Something/ then 'Nothing'
 when /Something else/ then 'I dont know'
 end

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

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


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

case expression
when condtion1
   function
when condition2
   function
else
   function
end

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

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

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

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

многие встроенные классы Ruby, такие как String, Range и Regexp, предоставляют свои собственные реализации оператора===, также известного как case-equality, 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. Другими словами, класс левого операнда будет определять, какая реализация метода === будет вызвана, поэтому позиции операнда не являются взаимозаменяемыми.

Регвыр Реализация===

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

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


$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

ссылка =>https://www.tutorialspoint.com/ruby/ruby_if_else.htm


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

a = "secondcase"

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

puts var_name
>> "bar"

в некоторых случаях это помогает компактировать код.


нет поддержки регулярных выражений в вашей среде? Е. Г. Shopify Редактор Скриптов (апрель, 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

Я ors в операторе метода класса, так как || имеет более высокий приоритет, чем .include?. Если вы Руби-фашистских, пожалуйста, представьте, что я использовал это . repl.это тест.