Как написать оператор switch в Ruby - PullRequest
1956 голосов
/ 04 июня 2009

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

Ответы [ 23 ]

2501 голосов
/ 04 июня 2009

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 во многих других языках, case в Ruby не имеет отказов , поэтому нет необходимости заканчивать каждый when break. Вы также можете указать несколько совпадений в одном предложении when, например when "foo", "bar".

419 голосов
/ 17 апреля 2011

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

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

200 голосов
/ 04 июня 2009

Это делается 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 (1st Edition, O'Reilly) говорится, что ключевое слово then, следующее за предложениями when, можно заменить на символ новой строки или точка с запятой (как в синтаксисе if then else). (Ruby 1.8 также допускает двоеточие вместо then ... Но этот синтаксис больше не разрешен в Ruby 1.9.)

91 голосов
/ 05 июля 2012

дело ... когда

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

С параметром:

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.

69 голосов
/ 07 декабря 2013

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

66 голосов
/ 01 августа 2013

В Ruby 2.0 вы также можете использовать лямбды в выражениях 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

(Пример взят из " Можно ли использовать процы с операторами 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 и что вы можете с ним сделать ".)

50 голосов
/ 16 октября 2012

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

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's case будет использовать для этого операнд равенства === (спасибо @JimDeville). Дополнительная информация доступна по адресу " Ruby Operators ". Это также может быть сделано на примере @mmdemirbas (без параметра), только этот подход более чист для таких случаев.

31 голосов
/ 03 июля 2014

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

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

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

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

30 голосов
/ 05 февраля 2016

Он называется 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
20 голосов
/ 18 июля 2016

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

Согласно Ruby Docs :

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

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

Пример: * * один тысяча двадцать-одна

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