Comment écrire une déclaration switch dans Ruby?

Comment puis-je écrire une déclaration d'échange dans Ruby?

1856
demandé sur Dmitry Grigoryev 2009-06-04 05:18:00

21 réponses

Ruby utilise case expression à la place.

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 compare l'objet dans la clause when avec l'objet dans la clause case en utilisant l'opérateur === . Par exemple, 1..5 === x , et non x === 1..5 .

cela permet des clauses sophistiquées when comme vu ci-dessus. Les gammes, les classes et toutes sortes de choses peuvent être testées pour plus que juste l'égalité.

Contrairement aux déclarations de switch dans de nombreuses autres langues, case de Ruby n'a pas fall-through , il n'est donc pas nécessaire de terminer chaque when par un break . Vous pouvez également spécifier plusieurs correspondances dans une seule clause when comme when "foo", "bar" .

2346
répondu Chuck 2018-04-04 09:03:49

case...when se comporte un peu de façon inattendue lors de la manipulation des classes. Cela est dû au fait qu'il utilise l'opérateur === .

Que l'opérateur fonctionne comme prévu avec des littéraux, mais pas avec des classes:

1 === 1           # => true
Fixnum === Fixnum # => false

cela signifie que si vous voulez faire un case ... when sur la classe d'un objet, cela ne fonctionnera pas:

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

imprimé "Ce n'est pas une chaîne".

heureusement, ceci est facilement résolu. L'opérateur === a été défini de sorte qu'il retourne true si vous l'utilisez avec une classe et fournissez une instance de cette classe comme deuxième opérande:

Fixnum === 1 # => true

en bref, le code ci-dessus peut être corrigé en supprimant le .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

j'ai frappé ce problème aujourd'hui tout en cherchant une réponse, et ce fut la première page apparaissant, donc j'ai pensé qu'il serait utile à d'autres dans mon même situation.

400
répondu kikito 2016-04-11 19:04:00

C'est fait par cas en Ruby. Voir aussi cet article sur Wikipedia .

Citée:

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

autre exemple:

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

autour de la page 123 (j'utilise Kindle) de la programmation Ruby Lanugage (1ère Édition, O'Reilly), il est dit le mot-clé then suivant les clauses when peut être remplacé par une nouvelle ligne ou point-virgule (comme dans la syntaxe if then else ). (Ruby 1.8 permet également un colon à la place de then ... Mais cette syntaxe n'est plus permise dans Ruby 1.9.)

190
répondu 太極者無極而生 2015-08-08 02:40:33
Affaire

...quand

pour ajouter d'autres exemples à réponse de Chuck :

avec paramètre:

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

sans paramètre:

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

s'il vous Plaît, soyez conscient de la question que kikito, avertit le rapport.

88
répondu mmdemirbas 2017-05-23 12:26:34

de nombreux langages de programmation, en particulier ceux dérivés de C, prennent en charge le soi-disant Switch Fallthrough . Je cherchais la meilleure façon de faire la même chose à Ruby et j'ai pensé que cela pourrait être utile à d'autres:

En C-comme langues fallthrough ressemble généralement à ceci:

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;
}

dans Ruby, la même chose peut être réalisée de la manière suivante:

case expression
when 'a', 'b', 'c'
  # Do something for a, b or c
when 'd', 'e'
  # Do something else for d or e
end

Ce n'est pas strictement équivalent, parce qu'il n'est pas possible de laisser 'a' exécuter un bloc de code avant de tomber dans 'b' ou 'c' , mais pour la plupart je le trouve assez similaire pour être utile de la même manière.

65
répondu Robert Kajic 2016-05-06 01:59:39

dans Ruby 2.0, vous pouvez également utiliser lambdas dans case déclarations, comme suit:

is_even = ->(x) { x % 2 == 0 }

case number
when 0 then puts 'zero'
when is_even then puts 'even'
else puts 'odd'
end

vous pouvez également créer vos propres comparateurs facilement en utilisant une structure avec un personnalisé ===

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

(exemple tiré de " ) est-ce que procs peut être utilisé avec les déclarations de cas dans Ruby 2.0? ".)

ou, avec une classe complète:

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

(exemple tiré de " Comment Un Rubis Cas De Déclaration De Travaux Et De Ce Que Vous Pouvez Faire Avec Lui ".)

64
répondu James Lim 2017-05-23 11:55:11

vous pouvez utiliser des expressions régulières, comme trouver un type de chaîne de caractères:

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 utilisera l'opérande d'égalité === pour ceci (merci @JimDeville). Des informations supplémentaires sont disponibles au " Ruby Operators ". Cela peut également être fait en utilisant l'exemple @mmdemirbas (sans paramètre), seulement cette approche est plus propre pour ces types de cas.

48
répondu Haris Krajina 2013-05-17 03:47:49

si vous êtes désireux de savoir comment utiliser un OR dans un boîtier Ruby switch:

Alors, dans un case , l'énoncé , est l'équivalent de || dans un if .

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

beaucoup d'autres choses que vous pouvez faire avec une déclaration de cas de rubis

30
répondu Manish Shrivastava 2015-08-08 02:46:05

ça s'appelle case et ça marche comme on pourrait s'y attendre, en plus de beaucoup plus de choses amusantes grâce à === qui implémente les tests.

case 5
  when 5
    puts 'yes'
  else
    puts 'else'
end

Maintenant, pour le plaisir:

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

et il s'avère que vous pouvez aussi remplacer une chaîne if/else arbitraire (c'est-à-dire, même si les tests n'impliquent pas une variable commune) par case en laissant de côté le paramètre initial case et en écrivant simplement des expressions où la première le match est ce que vous voulez.

case
  when x.nil?
    ...
  when (x.match /'^fn'/)
    ...
  when (x.include? 'substring')
    ...
  when x.gsub('o', 'z') == 'fnzrq'
    ...
  when Time.now.tuesday?
    ...
end
25
répondu DigitalRoss 2017-01-30 22:48:00

selon votre cas, vous pourriez préférer utiliser un hachage de méthodes.

S'il y a une longue liste de quand et que chacun d'eux a une valeur concrète à comparer avec (pas un intervalle), il sera plus efficace de déclarer un hachage de méthodes et ensuite d'appeler la méthode pertinente du hachage comme cela.

# 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])
20
répondu Alexander 2015-08-08 02:47:41

puisque switch case renvoie toujours un seul objet, nous pouvons directement imprimer son résultat:

puts case a
     when 0
        "It's zero"
     when 1
        "It's one"
     end
19
répondu Sonu Oommen 2015-08-08 02:42:17

Multi-valeur quand et la non-valeur de cas:

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

et une expression régulière solution ici:

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
19
répondu 123 2015-08-08 02:45:03

Ruby utilise le case pour écrire des énoncés d'interrupteur.

selon le Ruby Docs :

Cas énoncés sont d'une condition facultative, qui est dans le la position d'un argument case , et zéro ou plusieurs when clauses. La première clause when pour correspondre à la condition (ou pour évaluer à Boolean truth, si la condition est nulle) "gagne", et son code stanza est exécutée. La valeur de l'instruction de cas est la valeur de la when ou nil s'il n'existe pas de telle clause.

un énoncé de cas peut se terminer par une clause else . Chaque when a l'instruction peut avoir plusieurs valeurs candidates, séparées par des virgules.

exemple:

case x
when 1,2,3
  puts "1, 2, or 3"
when 10
  puts "10"
else
  puts "Some other number"
end

version courte:

case x
when 1,2,3 then puts "1, 2, or 3"
when 10 then puts "10"
else puts "Some other number"
end

et comme ce blog par Honeybadger décrit le cas Ruby;

peut être utilisé avec gammes :

case 5
when (1..10)
  puts "case statements match inclusion in a range"
end

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

peut être utilisé avec Regex :

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

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

peut être utilisé avec Procs et Lambdas :

case 40
when -> (n) { n.to_s == "40" }
  puts "lambdas!"
end

## => "lambdas"

aussi, peut être utilisé avec vos propres classes de match:

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
17
répondu Lahiru 2016-07-22 09:27:32

vous pouvez écrire des expressions de cas de deux façons différentes dans ruby.

  1. semblable à une série d'énoncés" si
  2. spécifie une cible à côté du cas et chaque clause" quand " est comparée à la cible.

1ère méthode

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

2ème

 case params[:unknown]
 when /Something/ then 'Nothing'
 when /Something else/ then 'I dont know'
 end
11
répondu ysk 2017-02-16 17:45:44

beaucoup de bonnes réponses mais j'ai pensé que je voudrais ajouter un factoid.. Si vous essayez de comparer des objets (Classes) assurez-vous d'avoir une méthode de vaisseau spatial (pas une blague) ou de comprendre comment ils sont comparés

Voici une bonne discussion sur le sujet http://www.skorks.com/2009/09/ruby-equality-and-object-comparison /

8
répondu jmansurf 2013-08-06 20:18:37

Vous pouvez le faire comme cela plus de façon naturelle,

case expression
when condtion1
   function
when condition2
   function
else
   function
end
8
répondu Navin 2016-05-26 09:15:12
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
5
répondu Prabhakar 2016-03-12 06:33:17

comme indiqué dans la plupart des réponses ci-dessus, l'opérateur === est utilisé sous la hotte sur les instructions case/when.

voici quelques informations supplémentaires sur cet opérateur.

opérateur d'égalité de cas: = = = =

plusieurs des classes intégrées de Ruby, telles que String, Range et Regexp, fournissent leurs propres implémentations de l'opérateur===, aussi connu sous le nom de case-equality, Triple equals ou threeequals. Parce qu'il est mis en œuvre différemment dans chaque classe, il va se comporter différemment selon le type d'objet, il a été appelé. Généralement, elle renvoie true si l'objet sur la droite "appartient à" ou "est un membre de" l'objet sur la gauche. Par exemple, il peut être utilisé pour tester si un objet est une instance d'une classe (ou un de ses sous-classes).

String === "zen"  # Output: => true
Range === (1..2)   # Output: => true
Array === [1,2,3]   # Output: => true
Integer === 2   # Output: => true

Le même résultat peut être obtenu avec d'autres méthodes qui sont probablement les mieux adaptés pour le travail, comme is_a? et instance_of?.

Gamme de la mise en Œuvre de l' ===

quand l'opérateur === est appelé sur un objet range, il renvoie true si la valeur à droite se situe dans la plage à gauche.

(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

rappelez-vous que l'opérateur === invoque la méthode === de l'objet de gauche. So (1..4) === 3 est équivalent à (1..4).= = = 3. En d'autres termes, la classe de l'opérande de gauche définira quelle implémentation de la méthode === sera appelée, si l'opérande de postes ne sont pas interchangeables.

Regexp mise en Œuvre de l' ===

renvoie true si la chaîne de caractères à droite correspond à l'expression régulière à gauche. /zen/ === "la pratique de zazen aujourd'hui" # Sortie: => true # est similaire à "la pratique de zazen aujourd'hui"=~ /zen/

La seule différence entre les deux exemples ci-dessus, c'est que, lorsqu'il existe une correspondance, === retourne true et =~ renvoie un entier, ce qui est une valeur vraie dans Ruby. Nous reviendrons à ce sujet bientôt.

4
répondu BrunoFacca 2016-07-06 16:07:17
$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

2
répondu Navneet 2017-11-13 09:28:06

j'ai commencé à utiliser:

a = "secondcase"

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

puts var_name
>> "bar"

il aide le code compact dans certains cas.

1
répondu deepfritz 2015-08-08 02:46:39

pas de support pour les expressions régulières dans votre environnement? Par exemple: Shopify Script Editor (April, 2018):

[erreur]: constante non initialisée RegExp

Une solution de contournement à la suite d'une combinaison de méthodes déjà précédemment dans ici et ici :

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

j'ai utilisé or s dans la classe de déclaration de méthode depuis || a une priorité plus élevée que .include? . Si vous êtes un ruby-nazi , s'il vous plaît imaginez que j'ai utilisé ce (item.include? 'A') || ... à la place. repl. .

0
répondu CPHPython 2018-04-18 11:29:29