Imaginez que vous avez besoin d’un moyen de vérifier la valeur d’un objet, et d’effectuer une action différente en fonction de cela. Le moyen de la programmation orientée objet est d’utiliser le polymorphisme, et nous verrons comment le faire dans une seconde.
Mais d’abord, regardons comment fonctionne l’expression case
, et comment vous pouvez l’utiliser pour atteindre le but mentionné ci-dessus.
Comment fonctionne l’expression ?
Il y a deux parties principales à l’expression case
. La clause case
, et la clause when
.
La clause when
est l’expression qui définit le récepteur de l’opérateur (par défaut ===
), et la clause case
définit l’argument qui lui est passé.
Voyons un exemple.
case awhen String #..end
Vous pouvez donc considérer l’exemple ci-dessus comme String === a
, ou String.===(a)
.
Enfin, il existe également une clause else
que vous pouvez utiliser lorsqu’il n’y a pas de correspondance.
case my_objectwhen String "This is a string"else "I have no idea what this is"end
L’opérateur triple égal (===)
Par défaut, case
utilise l’opérateur triple égal (===
) pour effectuer la comparaison.
Le problème avec ===
est qu’il n’a rien à voir avec l’égalité. Par défaut, il est aliasé à l’opérateur double equals (==
) qui vérifie normalement si deux objets ont une valeur équivalente, mais il peut être défini pour signifier n’importe quoi.
Par exemple, une plage le définit comme un alias pour includes?
, un regex le définit comme un alias pour match
, une classe pour is_a?
, un proc pour call
. Vous voyez l’idée.
Cet opérateur fonctionne comme prévu avec les littéraux, mais pas avec les classes :
1 === 1 # => trueNumeric === Numeric # => false
C’est parce que le ===
est un alias pour kind_of?
. Et voici la docs pour kind_of?
.
kind_of ?(class) → true or false
Retourne true si class est la classe d’obj, ou si class est une des superclasses d’obj ou des modules inclus dans obj.
Cela signifie que si vous voulez faire un case ... when
sur la classe d’un objet, cela ne fonctionnera pas :
obj = 'Hi'case obj.classwhen String "It's a string"end
C’est parce que, cela se traduit par String === String
. Et cela renvoie false
.
L’opérateur par défaut
L’expression case
a un opérateur par défaut. Et cela signifie que vous n’avez pas besoin de le spécifier. C’est très bien, car vous pouvez simplement écrire when String
et il utilise par défaut l’opérateur ===
.
Mais, il y a des moments où vous voulez utiliser un opérateur différent. Et Ruby vous permet de le faire. Voici comment.
casewhen a < 3 "Smaller than 3"end
Case is an expression
Comme son nom l’indique, l’ensemble est une expression. Cela signifie qu’il s’évalue à une valeur. Vous pouvez donc affecter le résultat de l’expression entière case
à une variable, comme ceci .
value = case when a < 3 "Smaller than 3" end
Il n’y a pas de chute
Si vous venez d’autres langages, vous avez probablement utilisé une déclaration switch
ou quelque chose de similaire, et vous avez remarqué que case
n’utilise pas de mots-clés comme break
pour rompre le flux.
C’est parce qu’il n’y a pas de retombée avec case
. Il renvoie simplement la valeur de l’expression qui a été mise en correspondance et c’est tout.
Multiples correspondances
Jusqu’à présent, vous n’avez utilisé qu’une seule valeur pour la clause when
. Mais vous pouvez utiliser plusieurs valeurs.
case awhen 1..3 "Small number"end
Matching regexes
Vous pouvez utiliser les expressions case
pour faire correspondre n’importe quoi. Mais au cas où ce ne serait pas évident, vous pourriez aussi faire correspondre des regex, ou des lambdas. Voici un exemple.
even = ->(x) { x % 2 == 0 }case awhen even "It's even"when /^+$/ "It's an integer"end
Définissez les vôtres
Un des faits les moins connus est que vous pouvez définir vos propres comparateurs.
Text = Struct.new(:min_length) do def ===(string) string.size > min_length && string.is_a?(String) endendcase awhen Text.new(100) "It's text"end
Dans l’exemple ci-dessus, si a
est une chaîne de plus de 100 caractères, alors l’expression case
retournera It's text
.
Utiliser le polymorphisme à la place
Je ne vais pas m’étendre ici sur les avantages de la POO, vous pouvez en savoir plus à ce sujet dans l’article Programmation orientée objet avec Ruby, mais je vais vous montrer comment vous pouvez utiliser le polymorphisme pour remplacer une expression case
.
La version cas
class Person attr_reader :country def initialize(country) @country = country end def nationality case country when "USA" "This guy is an American" when "Romania" "This guy is a Romanian" end endendjohn = Person.new("USA")puts john.nationality # => This guy is an American
La version POO
class Person attr_reader :country def initialize(country) @country = country end def nationality country.nationality endendclass America def nationality "This guy is an American" endendclass Romania def nationality "This guy is a Romanian" endendjohn = Person.new(America.new)puts john.nationality # => This guy is an American
C’est une bonne idée de supprimer autant de code de contrôle de flux (i.c’est-à-dire if
s, et case
expressions) que possible. Cela améliore le respect du principe de responsabilité unique et rend le programme plus lisible en général.