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

Как мне написать switchзаявление в Ruby?

4.06.2009 01:18:00
24 ОТВЕТА
РЕШЕНИЕ

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

2658
4.04.2018 09:03:49
Вы также можете сделать регулярное выражение для переданного аргумента: когда / thisisregex / следующая строка выводит «Это найденное совпадение с номером 1 # {$ 1}» end
Automatico 20.01.2013 15:34:23
Также стоит отметить, что вы можете сократить свой код, поместив оператор whenand returnв одну строку:when "foo" then "bar"
Alexander - Reinstate Monica 11.05.2018 23:40:43
Важное замечание: В отличие от switchоператоров во многих других языках, Ruby's caseне имеет провала , поэтому нет необходимости заканчивать каждое whenна a break.
janniks 3.09.2018 09:45:57
Так много голосов до сих пор даже не упоминание ключевого слова then. Пожалуйста, посмотрите также другие ответы.
Clint Pachl 4.06.2019 23:05:04

Это делается с помощью caseRuby. Также см. « Смена оператора » в Википедии.

Цитируется:

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

217
9.12.2019 19:48:49
when (-1.0/0.0)..-1 then "Epic fail"
Andrew Grimm 17.04.2011 23:49:45
Это ответ, который я использовал, потому что я определяю переменную на основе результатов переключения регистра. Вместо того, чтобы произносить type = #{score}каждую строку, я могу просто скопировать то, что вы сделали. Гораздо более элегантно, мне также нравятся однострочники намного лучше (если это возможно)
onebree 12.05.2015 14:06:10
Я знаю, что это не имеет отношения к сути ответа, но 4 также является идеальным квадратом.
Nick Moore 20.01.2020 16:15:58

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

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

438
22.08.2019 21:23:06
obj = 'привет'; case obj; когда «привет» ставит конец «Это привет»
Sugumar Venkatesan 10.02.2017 09:59:54
Имея .classучастие в Интересно отметить, спасибо. Конечно, это вполне подходящее поведение (хотя я мог видеть, как это может быть распространенной ошибкой думать, что это напечатало бы It is a string) ... вы тестируете класс какого-то произвольного объекта, а не сам объект. Так, например: case 'hello'.class when String then "String!" when Class then "Class!" else "Something else" endрезультаты: "Class!"Это работает так же для 1.class, {}.classи т.д. каплепадения .class, мы получаем "String!"или "Something else"для этих различных значений.
lindes 11.04.2019 07:14:14

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

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

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

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

Пожалуйста, имейте в виду " Как написать оператор switch в Ruby ", о котором kikito предупреждает.

105
25.11.2019 23:11:20
Спасибо, это было полезно для нескольких вариантов на одной строке. Я пытался использоватьor
sixty4bit 9.12.2014 20:19:52

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

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). Дополнительная информация доступна на " Рубин Операторы ". Это также можно сделать с помощью примера @mmdemirbas (без параметра), только этот подход более чист для таких случаев.

52
17.05.2013 03:47:49

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

72
23.05.2017 11:55:11

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

" Рубиновое равенство и сравнение объектов " - хорошая дискуссия на эту тему.

9
25.11.2019 23:18:30
Для справки, метод «космический корабль» - это метод <=>, который используется для возврата -1, 0, 1 или нуля в зависимости от того, возвращает ли сравнение меньше, равно, больше или не сопоставимо соответственно. В документации Ruby Comparable модуля это объясняется.
the Tin Man 11.09.2013 15:18:42

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

puts case a
     when 0
        "It's zero"
     when 1
        "It's one"
     end
21
8.08.2015 02:42:17

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

73
6.05.2016 01:59:39

Многозначный случай и случай без значения:

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
20
8.08.2015 02:45:03
почему не просто case some_string, when /\d/, (stuff), when /[a-zA-Z]/, (stuff), end(где ,означает
Doorknob 26.01.2014 03:21:15
о, и первая часть уже покрыта этим ответом , и многие ответы уже упоминают регулярное выражение. Честно говоря, этот ответ не добавляет ничего нового, и я голосую и голосую, чтобы удалить его.
Doorknob 26.01.2014 03:22:55
@DoorknobofSnow Это показывает, что вы можете использовать решение Regex и разделенные запятыми значения в случае переключения. Не уверен, почему решение так сильно болит.
123 27.01.2014 05:19:43
так, если они получили "F", законную оценку, это их вина, что ваш код пропускает дело?
Mike Graf 20.06.2014 18:48:38
Мне нравится юмор этого и тот факт, что он демонстрирует, что вы можете сопоставить строки с делом.
emery 7.05.2015 14:14:22

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

Таким образом, в caseутверждении a ,является эквивалентом ||в ifутверждении.

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

Смотрите " Как работает Ruby Case case и что вы можете с ним сделать ".

34
25.11.2019 23:12:41
форматирование кода не работает в связанной статье :-)
froderik 23.12.2018 16:54:20

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

a = "secondcase"

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

puts var_name
>> "bar"

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

1
8.08.2015 02:46:39
Код, подобный этому, обычно должен выполняться с использованием оператора Hash, а не caseоператора.
Tom Lord 15.07.2016 14:55:20
Использование хэша будет быстрее, когда этот переключатель станет большим.
the Tin Man 26.11.2019 19:38:51

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

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

# 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])
22
26.11.2019 20:18:35

Он называется 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
33
30.01.2017 22:48:00
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
6
12.03.2016 06:33:17
Это поможет, если вы предоставите объяснение, почему это предпочтительное решение, и объясните, как оно работает. Мы хотим обучать, а не просто предоставлять код.
the Tin Man 26.11.2019 20:16:20

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

case expression
when condtion1
   function
when condition2
   function
else
   function
end
10
26.05.2016 09:15:12

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

Вот дополнительная информация об этом операторе:

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

Многие из встроенных в Ruby классов, такие как String, Range и Regexp, предоставляют свои собственные реализации ===оператора, также известные как «case-равенства», «тройное равенство» или «тройное равенство». Поскольку он реализован по-разному в каждом классе, он будет вести себя по-разному в зависимости от типа объекта, к которому он был вызван. Как правило, он возвращает 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/ === "practice zazen today"  # Output: => true
# is similar to
"practice zazen today"=~ /zen/

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

7
26.11.2019 20:15:21

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

Согласно caseдокументации:

Операторы case состоят из необязательного условия, которое находится в позиции аргумента case, и нуля или более whenпредложений. Первое whenпредложение, которое соответствует условию (или оценивается как логическая истина, если условие имеет значение null) «выигрывает», и выполняется его кодовая часть. Значением оператора 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

И как « утверждение случая Руби - продвинутые методы » описывает Руби 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
22
25.11.2019 23:15:02

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

  1. Похож на серию ifзаявлений
  2. Укажите цель рядом с caseи каждое whenпредложение сравнивается с целью.
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
12
26.11.2019 20:17:36
Хотя ваш код может ответить на этот вопрос, вы должны добавить хотя бы краткое описание того, что делает ваш код и как он решает начальную проблему.
user1438038 16.02.2017 10:16:15
Я рассмотрю этот совет в будущем.
ysk 5.04.2017 11:59:01
$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

Смотрите " Ruby - если ... еще, case, если только " для получения дополнительной информации.

3
26.11.2019 20:10:08

Нет поддержки регулярных выражений в вашей среде? Например, редактор сценариев 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?. Если вы рубин-нацист , пожалуйста, представьте, что я использовал это (item.include? 'A') || ...вместо этого. Репл.ит тест.

1
18.04.2018 11:29:29

Мы можем написать оператор 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
0
28.01.2019 06:02:46
Это не сработает; Рубиновые ключевые слова (например. case, when, end) Чувствительны к регистру и не может быть в верхнем регистре , как это.
sondra.kinsey 20.05.2019 13:42:07
NoMethodError (undefined method CASE 'для main: Object) `. Как сказал @ sondra.kinsey, вы не можете использовать верхний регистр. Руби будет думать, что это ПОСТОЯННО.
the Tin Man 26.11.2019 19:59:41

Важно подчеркнуть запятую ( ,) в whenпредложении. Он действует как ||из ifзаявления, то есть, он делает или сравнение и не И сравнение между разделителями выражений whenпункта. Смотрите следующее описание случая:

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

xне менее 2, но возвращаемое значение "apple". Почему? Потому что xбыло 3, а так как ',`` acts as an|| , it did not bother to evaluate the expressionх <2 '.

Вы можете подумать, что для выполнения AND , вы можете сделать что-то вроде этого ниже, но это не работает:

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

Это не работает, потому что (3 && x > 2)оценивается как true, а Ruby принимает значение True и сравнивает его xс значением ===, которое не соответствует истине, поскольку xравно 3.

Чтобы сделать &&сравнение, вам нужно рассматривать caseкак if/ elseблок:

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

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

1
26.11.2019 19:49:01
Это не похоже на хороший стиль кодирования для меня. Использование редкого альтернативного синтаксиса излишне запутывает. Почему бы не использовать нормальный if...elsif? Похоже, вы пытаетесь смешать заявление случая и условие. Почему? Просто поместите условную внутри группы При блоке, например. when 3; ( x < 2 ) ? 'apple' : 'orange'
sondra.kinsey 20.05.2019 13:40:18

caseОператор оператор, как и switchв других языках.

Это синтаксис switch...caseв C:

switch (expression)
​{
    case constant1:
      // statements
      break;
    case constant2:
      // statements
      break;
    .
    .
    .
    default:
      // default statements
}

Это синтаксис case...whenв Ruby:

case expression
  when constant1, constant2 #Each when statement can have multiple candidate values, separated by commas.
     # statements 
     next # is like continue in other languages
  when constant3
     # statements 
     exit # exit is like break in other languages
  .
  .
  .
  else
     # statements
end

Например:

x = 10
case x
when 1,2,3
  puts "1, 2, or 3"
  exit
when 10
  puts "10" # it will stop here and execute that line
  exit # then it'll exit
else
  puts "Some other number"
end

Для получения дополнительной информации см. caseДокументацию.

0
26.11.2019 19:54:52