Stel je voor dat je een manier nodig hebt om de waarde van een object te controleren, en op basis daarvan een andere actie uit te voeren. De Object Georiënteerd Programmeren manier is om polymorfisme te gebruiken, en we zullen zien hoe je dat in een seconde kunt doen.
Maar laten we eerst eens kijken hoe de case
expressie werkt, en hoe je het kunt gebruiken om het hierboven genoemde doel te bereiken.
Hoe werkt de case?
Er zijn twee hoofdonderdelen aan de case
expressie. De case
-clausule, en de when
-clausule.
De when
clausule is de expressie die de ontvanger van de operator definieert (standaard ===
), en de case
clausule definieert het argument dat aan de operator wordt doorgegeven.
Laten we eens een voorbeeld bekijken.
case awhen String #..end
Dus je kunt aan bovenstaand voorbeeld denken als String === a
, of String.===(a)
.
Ten slotte is er ook nog een else
-clausule die je kunt gebruiken voor als er geen overeenkomst is.
case my_objectwhen String "This is a string"else "I have no idea what this is"end
De drievoudige gelijk-operator (===)
Bestandaard gebruikt case
de drievoudige gelijk-operator (===
) om de vergelijking uit te voeren.
Het probleem met ===
is dat het niets met gelijkheid te maken heeft. Het is standaard aliased naar de dubbele gelijkheid operator (==
) die normaal controleert of twee objecten een gelijke waarde hebben, maar het kan worden gedefinieerd om van alles te betekenen.
Bijv. een range definieert het als een alias voor includes?
, een regex definieert het als een alias voor match
, een class voor is_a?
, een proc voor call
. Je snapt het idee.
Die operator werkt zoals verwacht met literals, maar niet met classes:
1 === 1 # => trueNumeric === Numeric # => false
Dat komt omdat de ===
een alias is voor kind_of?
. En hier zijn de docs voor kind_of?
.
kind_van?(class) → true of false
Returns true als class de class van obj is, of als class een van de superklasses van obj is of modules die in obj zijn opgenomen.
Dit betekent dat als je een case ... when
over de klasse van een object wilt doen, dit niet zal werken:
obj = 'Hi'case obj.classwhen String "It's a string"end
Dat is omdat, het vertaalt naar String === String
. En dat levert false
op.
De standaard operator
De case
expressie heeft een standaard operator. En dat betekent dat je hem niet hoeft te specificeren. Dat is heel mooi, want je kunt gewoon when String
schrijven en het gaat standaard naar de ===
operator.
Maar, er zijn momenten dat je een andere operator wilt gebruiken. En Ruby staat je toe om dat te doen. Hier lees je hoe.
casewhen a < 3 "Smaller than 3"end
Case is een expressie
Net zoals de naam al zegt, is het hele ding een expressie. Dat betekent dat het naar een waarde wordt geëvalueerd. Dus je kunt het resultaat van de hele case
expressie aan een variabele toewijzen, zoals dit.
value = case when a < 3 "Smaller than 3" end
Er is geen fall-through
Als je uit andere talen komt, heb je waarschijnlijk wel eens een switch
statement of iets dergelijks gebruikt, en hebt u gemerkt dat case
geen trefwoorden gebruikt zoals break
om de stroom te onderbreken.
Dat komt omdat er geen fall-through is met case
. Het retourneert alleen de waarde van de expressie waarop is gematcht en dat is het.
Meerdere matches
Tot nu toe hebt u slechts één waarde gebruikt voor de when
-clausule. Maar u kunt meerdere waarden gebruiken.
case awhen 1..3 "Small number"end
Het matchen van regexes
U kunt case
expressies gebruiken om met alles te matchen. Maar voor het geval het niet duidelijk is, je kunt ook regexen, of lambdas gebruiken. Hier is een voorbeeld.
even = ->(x) { x % 2 == 0 }case awhen even "It's even"when /^+$/ "It's an integer"end
Definieer je eigen
Een van de minder bekende feiten is dat je je eigen comparators kunt definiëren.
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
In het bovenstaande voorbeeld, als a
een tekenreeks is van meer dan 100 tekens, dan zal de case
expressie It's text
teruggeven.
Gebruik in plaats daarvan polymorfisme
Ik ga hier niet in op de voordelen van OOP, daar kun je meer over lezen in het Object-georiënteerd programmeren met Ruby artikel, maar ik ga je laten zien hoe je polymorfisme kunt gebruiken om een case
expressie te vervangen.
De case versie
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
De OOP versie
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
Het is een goed idee om zo veel mogelijk flow control code te verwijderen (i.d.w.z. if
s, en case
expressies) zoveel mogelijk te verwijderen. Het verbetert het naleven van het Single Responsibility Principle en maakt het programma leesbaarder in het algemeen.