Comment écrire une instruction switch en Ruby?
Ruby utilise plutôt l'expression 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 compare l'objet de la clause when
à celui de la clause case
à l'aide de l'opérateur ===
. Par exemple, 1..5 === x
et non pas x === 1..5
.
Cela permet de créer des clauses when
sophistiquées, comme indiqué ci-dessus. Les gammes, les classes et toutes sortes de choses peuvent être testées plutôt que simplement l'égalité.
Contrairement aux instructions switch
dans de nombreuses autres langues, case
de Ruby n’a pas de chute directe , 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
, telle que when "foo", "bar"
.
case...when
se comporte de manière inattendue lors du traitement des classes. Cela est dû au fait qu'il utilise l'opérateur ===
.
Cet opérateur fonctionne comme prévu avec les littéraux, mais pas avec les 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 or number')
end
Imprimera "Ce n'est pas une chaîne ou un nombre".
Heureusement, ceci est facilement résolu. L'opérateur ===
a été défini pour qu'il renvoie true
si vous l'utilisez avec une classe et fournissez une instance de cette classe en tant que second 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 or number')
end
J'ai trouvé ce problème aujourd'hui alors que je cherchais une réponse, et comme c'était la première page qui apparaissait, je me suis dit que cela pourrait être utile à d'autres dans la même situation.
C'est fait par cas en Ruby. Voir aussi cet article sur Wikipedia .
Cité
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
Un 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
À la page 123 environ (j'utilise Kindle) de , le Ruby Programming Lanugage (1re édition, O'Reilly), dit le mot-clé then
suivant les clauses when
peut être remplacé par un retour à la ligne ou un point-virgule (comme dans la syntaxe if then else
]. (Ruby 1.8 autorise également deux points au lieu de then
... Mais cette syntaxe n'est plus autorisée dans Ruby 1.9.)
Pour ajouter plus d'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 le problème que kikito met en garde.
De nombreux langages de programmation, en particulier ceux dérivés du C, prennent en charge le soi-disant Switch Fallthrough . Je cherchais le meilleur moyen de faire de même dans Ruby et je pensais que cela pourrait être utile aux autres:
Dans les langages de type C, l’incroyable chute ressemble à 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;
}
En Ruby, on peut atteindre le même objectif 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, car il n'est pas possible de laisser 'a'
exécuter un bloc de code avant de tomber dans 'b'
ou 'c'
, mais je le trouve assez similaire pour l'être utile de la même manière.
Dans Ruby 2.0, vous pouvez également utiliser lambdas dans les instructions case
, 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 facilement vos propres comparateurs 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 " Les procédures peuvent-elles être utilisées avec des instructions case 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 une instruction de cas Ruby fonctionne et ce que vous pouvez en faire) ".)
Vous pouvez utiliser des expressions régulières, telles que la recherche d'un type de chaîne:
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
de Ruby utilisera l'opérande d'égalité ===
pour cela (merci @JimDeville). Des informations complémentaires sont disponibles sur " Opérateurs Ruby ". Cela peut aussi être fait en utilisant l'exemple @mmdemirbas (sans paramètre), seule cette approche est plus propre pour ces types de cas.
Si vous souhaitez savoir comment utiliser une condition OR dans un boîtier de commutateur Ruby:
Ainsi, dans une instruction case
, un ,
est l'équivalent de ||
dans une instruction if
.
case car
when 'Maruti', 'Hyundai'
# Code here
end
Beaucoup d'autres choses que vous pouvez faire avec une instruction de cas Ruby
Elle s'appelle case
et fonctionne comme prévu, avec bien plus de choses amusantes grâce à ===
qui implémente les tests.
case 5
when 5
puts 'yes'
else
puts 'else'
end
Maintenant pour s'amuser:
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 également remplacer une chaîne if/else (c'est-à-dire même si les tests ne comportent pas de variable commune) avec case
en omettant le paramètre initial case
et en écrivant simplement expressions où la première correspondance 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
Selon votre cas, vous préférerez peut-être utiliser un hash de méthodes.
S'il existe une longue liste de moments et que chacun d'entre eux a une valeur concrète à comparer (et non un intervalle), il sera plus efficace de déclarer un hachage de méthodes, puis d'appeler la méthode correspondante à partir du hachage.
# 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])
Ruby utilise le case
pour écrire des instructions de commutateur.
Selon le Ruby Docs :
Les instructions case comprennent une condition facultative, qui se trouve dans la position d'un argument de
case
et de zéro ou plusieurs clauseswhen
. La première clausewhen
pour faire correspondre la condition (ou pour évaluer la vérité booléenne, si la condition est nulle) "gagne" et sa strophe de code est exécutée. La valeur de l'instruction case est la valeur de la clausewhen
réussie, ounil
s'il n'existe pas de telle clause.Une instruction case peut se terminer par une clause
else
. Chaquewhen
une 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 plus 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 de Honeybadger décrit Ruby Case;
Peut être utilisé avec Ranges :
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"
Vous pouvez également utiliser vos propres classes de correspondance:
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
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
Cas multi-valeur quand et sans valeur:
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 solution expression régulière 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
Vous pouvez écrire des expressions de casse de deux manières différentes dans Ruby.
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
Vous pouvez faire comme ça de manière plus naturelle,
case expression
when condtion1
function
when condition2
function
else
function
end
Si vous essayez de comparer des objets (classes), assurez-vous de disposer d'une méthode de vaisseau spatial (pas d'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/
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
Comme indiqué dans de nombreuses réponses ci-dessus, l'opérateur === est utilisé sous le capot des déclarations case/when.
Voici quelques informations supplémentaires sur cet opérateur.
De nombreuses classes intégrées de Ruby, telles que String, Range et Regexp, fournissent leurs propres implémentations de l'opérateur ===, également connu sous le nom d'égalité de cas, triple égal ou triple. Comme il est implémenté différemment dans chaque classe, il se comportera différemment selon le type d'objet sur lequel il a été appelé. Généralement, il retourne vrai si l'objet de droite "appartient à" ou "est un membre de" l'objet de gauche. Par exemple, il peut être utilisé pour tester si un objet est une instance d'une classe (ou de l'une 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 conviennent probablement le mieux, telles que is_a? et instance_of ?.
Lorsque l'opérateur === est appelé sur un objet d'intervalle, il renvoie true si la valeur de droite se situe dans l'intervalle de 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 === appelle la méthode === de l'objet de gauche. Donc (1..4) === 3 est équivalent à (1..4). === 3. En d’autres termes, la classe de l’opérande de gauche déterminera quelle implémentation de la méthode === sera appelé, donc les positions d'opérande ne sont pas interchangeables.
Renvoie true si la chaîne à droite correspond à l'expression régulière à gauche./zen/=== "pratiquez zazen aujourd'hui" # Résultat: => vrai # est similaire à "pratiquez zazen aujourd'hui" = ~/zen /
La seule différence pertinente entre les deux exemples ci-dessus est que, lorsqu'il y a correspondance, === renvoie true et = ~ renvoie un entier, qui est une valeur de vérité en Ruby. Nous y reviendrons bientôt.
$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
J'ai commencé à utiliser:
a = "secondcase"
var_name = case a
when "firstcase" then "foo"
when "secondcase" then "bar"
end
puts var_name
>> "bar"
Cela aide le code compact dans certains cas.
Il est essentiel de mettre la virgule ',' dans une clause when comme un || d’une instruction if, c’est-à-dire qu’il effectue une comparaison OR et non une comparaison AND entre les expressions délimitées de la clause when. Vérifiez donc la déclaration de cas ci-dessous. Clairement, x n’est pas inférieur à 2, mais la valeur de retour est "Apple". Pourquoi? Puisque x était 3 et que ',' agissait comme un ||, l'évaluation de l'expression 'x <2' n'a pas été une peine.
x = 3
case x
when 3, x < 2 then 'Apple'
when 3, x > 2 then 'orange'
end
=> "Apple"
Vous pourriez penser que pour effectuer un AND, vous pouvez faire quelque chose comme ceci ci-dessous. Mais ça ne marche pas. C'est parce que (3 && x> 2) est évalué à true et que Ruby prend la valeur True et la compare à x avec ===, ce qui n'est évidemment pas vrai, car x est 3.
case x
when (3 && x < 2) then 'Apple'
when (3 && x > 2) then 'orange'
end
=> nil
Pour faire une comparaison &&, vous devrez traiter les cas comme et si sinon bloquer:
case
when x == 3 && x < 2 then 'Apple'
when x == 3 && x > 2 then 'orange'
end
Dans le livre Langage de programmation Ruby, Matz indique que cette dernière forme est la forme simple (et rarement utilisée), qui n'est rien d'autre qu'une syntaxe alternative pour if/elsif/else. Cependant, que ce soit rarement utilisé ou non, je ne vois pas d'autre moyen d'attacher plusieurs expressions && pour une clause 'when' donnée.
Pas de support pour les expressions régulières dans votre environnement? Par exemple. Shopify Editeur de script (avril 2018):
[Erreur]: constante non initialisée RegExp
Une solution de contournement après une combinaison de méthodes déjà couvertes 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 l'instruction de méthode de classe car ||
a une priorité supérieure à .include?
. Si vous êtes un Ruby-Nazi , imaginez que j'ai utilisé ce (item.include? 'A') || ...
à la place. repl.it test.
Nous pouvons écrire une instruction switch pour plusieurs conditions.
Par exemple,
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