Articles

Come scrivere un’espressione di caso in Ruby

Posted on

Immaginate di aver bisogno di un modo per controllare il valore di un oggetto, ed eseguire un’azione diversa in base a questo. Il modo di programmazione orientata agli oggetti è quello di usare il polimorfismo, e vedremo come farlo tra un secondo.

Ma prima, vediamo come funziona l’espressione case, e come si può usare per raggiungere l’obiettivo di cui sopra.

Come funziona il caso?

Ci sono due parti principali nell’espressione case. La clausola case e la clausola when.

La clausola when è l’espressione che definisce il destinatario dell’operatore (di default ===), e la clausola case definisce l’argomento passato ad esso.

Vediamo un esempio.

case awhen String #..end

Quindi potete pensare all’esempio precedente come String === a, o String.===(a).

Infine, c’è anche una clausola else che potete usare per quando non c’è corrispondenza.

case my_objectwhen String "This is a string"else "I have no idea what this is"end

L’operatore triplo uguale (===)

Di default, case usa l’operatore triplo uguale (===) per fare il confronto.

La cosa con === è che non ha nulla a che fare con l’uguaglianza. Per impostazione predefinita, è un alias dell’operatore doppio equals (==) che normalmente controlla se due oggetti hanno un valore equivalente, ma può essere definito per significare qualsiasi cosa.

Per esempio, un range lo definisce come alias per includes?, una regex lo definisce come alias per match, una classe per is_a?, un proc per call. Avete capito bene.

Quell’operatore funziona come previsto con i letterali, ma non con le classi:

1 === 1 # => trueNumeric === Numeric # => false

Questo perché il === è un alias per kind_of?. Ed ecco la documentazione per kind_of?.

kind_of?(class) → true o false

Ritorna true se class è la classe di obj, o se class è una delle superclassi di obj o dei moduli inclusi in obj.

Questo significa che se volete fare un case ... when sulla classe di un oggetto, questo non funzionerà:

obj = 'Hi'case obj.classwhen String "It's a string"end

Questo perché, si traduce in String === String. E questo restituisce false.

L’operatore predefinito

L’espressione case ha un operatore predefinito. E questo significa che non devi specificarlo. Questo è molto bello, perché puoi semplicemente scrivere when String e l’operatore predefinito è ===.

Ma ci sono momenti in cui vuoi usare un operatore diverso. E Ruby vi permette di farlo. Ecco come fare.

casewhen a < 3 "Smaller than 3"end

Case è un’espressione

Proprio come dice il nome, il tutto è un’espressione. Ciò significa che valuta un valore. Quindi potete assegnare il risultato dell’intera case espressione ad una variabile, così.

value = case when a < 3 "Smaller than 3" end

Non c’è nessun fall-through

Se vieni da altri linguaggi, probabilmente hai usato un’istruzione switch o qualcosa di simile, e avrete notato che case non usa parole chiave come break per interrompere il flusso.

Questo perché non c’è nessun fall-through con case. Restituisce semplicemente il valore dell’espressione che è stata abbinata e basta.

Combinazioni multiple

Fino ad ora, hai usato solo un valore per la clausola when. Ma puoi usare valori multipli.

case awhen 1..3 "Small number"end

Corrispondenza delle regex

Puoi usare le espressioni case per far corrispondere qualsiasi cosa. Ma nel caso in cui non sia ovvio, potete anche abbinare delle regex, o dei lambda. Ecco un esempio.

even = ->(x) { x % 2 == 0 }case awhen even "It's even"when /^+$/ "It's an integer"end

Definisci il tuo

Uno dei fatti meno conosciuti è che puoi definire i tuoi comparatori.

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

Nell’esempio precedente, se a è una stringa di più di 100 caratteri, allora l’espressione case restituirà It's text.

Utilizzate il polimorfismo invece

Non mi addentrerò qui nei benefici dell’OOP, potete leggere di più in merito nell’articolo Programmazione orientata agli oggetti con Ruby, ma vi mostrerò come potete usare il polimorfismo per sostituire un’espressione case.

La versione del caso

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 versione OOP

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

È una buona idea eliminare la maggior parte del codice di controllo del flusso (i.e. ifs, e case espressioni) il più possibile. Migliora l’aderenza al principio di responsabilità unica e rende il programma più leggibile in generale.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *