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

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

Ответ 1

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

Ответ 2

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 or number')
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 or number')
end

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

Ответ 3

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

Ответ 4

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

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

Ответ 5

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

Ответ 6

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

Ответ 7

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

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

Ответ 9

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

Ответ 10

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

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

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

Ответ 11

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

Ответ 12

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

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

Ответ 13

Многозначный случай 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

Ответ 14

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

Ответ 15

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

case expression
when condtion1
   function
when condition2
   function
else
   function
end

Ответ 16

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

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

Ответ 17

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

Ответ 18

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

Ответ 20

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

a = "secondcase"

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

puts var_name
>> "bar"

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

Ответ 21

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

Ответ 22

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

Ответ 23

Важно подчеркнуть запятую ',' в предложении когда действует как || оператора if, то есть он выполняет сравнение ИЛИ, а не сравнение И между выражениями с разделителями в предложении когда. Так что ознакомьтесь с приведенным ниже выражением. Ясно, что x не меньше 2, но возвращаемое значение - "яблоко". Почему? Поскольку x равнялся 3, а поскольку ',' действует как ||, он не потрудился оценить выражение 'x & lt; 2'.

x = 3
case x
  when 3, x < 2 then 'apple'
  when 3, x > 2 then 'orange'
end
 => "apple"

Вы можете подумать, что для выполнения AND, вы можете сделать что-то вроде этого ниже. Но это не работает. Это потому, что (3 & x> 2) оценивается как true, а ruby принимает значение True и сравнивает его с x с ===, что, очевидно, неверно, поскольку x равен 3.

case x
  when (3 && x < 2) then 'apple'
  when (3 && x > 2) then 'orange'
end
 => nil 

Чтобы && Для сравнения, вам придется рассматривать случай как, а если еще блок:

case
  when x == 3 && x < 2 then 'apple'
  when x == 3 && x > 2 then 'orange'
end

В книге Ruby Programming Language Матц говорит, что эта последняя форма является простой (и редко используемой) формой, которая является не чем иным, как альтернативным синтаксисом для if/elsif/else. Однако, независимо от того, используется ли он редко или нет, я не вижу другого способа присоединить несколько && & выражения для данного предложения "когда".