Articles

Jak napisać Wyrażenie Przypadku w Ruby

Posted on

Wyobraź sobie, że potrzebujesz sposobu na sprawdzenie wartości obiektu i wykonanie innej akcji na tej podstawie. W programowaniu obiektowym sposobem na to jest użycie polimorfizmu, a jak to zrobić zobaczymy za chwilę.

Ale najpierw przyjrzyjmy się jak działa wyrażenie case i jak możesz go użyć aby osiągnąć cel wspomniany powyżej.

Jak działa case?

Są dwie główne części wyrażenia case. Klauzula case oraz klauzula when.

Klauzula when jest wyrażeniem określającym odbiorcę operatora (domyślnie ===), a klauzula case określa przekazywany do niego argument.

Zobaczmy przykład.

case awhen String #..end

Możesz więc myśleć o powyższym przykładzie jako String === a, lub String.===(a).

Na koniec, istnieje również klauzula else, której można użyć, gdy nie ma dopasowania.

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

Operator potrójnego zrównania (==)

Domyślnie, case używa operatora potrójnego zrównania (===) do wykonania porównania.

Sytuacja z === jest taka, że nie ma on nic wspólnego z równością. Domyślnie jest to alias do operatora double equals (==), który normalnie sprawdza, czy dwa obiekty mają równoważną wartość, ale można go zdefiniować tak, aby oznaczał cokolwiek.

Na przykład, zakres definiuje go jako alias dla includes?, regex definiuje go jako alias dla match, klasa dla is_a?, proc dla call. Rozumiemy to.

Ten operator działa zgodnie z oczekiwaniami z literałami, ale nie z klasami:

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

To dlatego, że === jest aliasem dla kind_of?. A oto docs dla kind_of?.

kind_of?(class) → true or false

Zwraca true, jeśli class jest klasą obj, lub jeśli class jest jedną z nadklas obj lub modułów zawartych w obj.

To oznacza, że jeśli chcesz zrobić case ... when nad klasą obiektu, to nie zadziała:

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

To dlatego, że, to tłumaczy się na String === String. A to zwraca false.

Operator domyślny

Wyrażenie case posiada operator domyślny. A to oznacza, że nie musisz go określać. Jest to bardzo miłe, ponieważ możesz po prostu napisać when String i domyślnie zostanie użyty operator ===.

Ale są sytuacje, kiedy chcesz użyć innego operatora. I Ruby pozwala ci na to. Oto jak.

casewhen a < 3 "Smaller than 3"end

Case jest wyrażeniem

Tak jak mówi nazwa, cała ta funkcja jest wyrażeniem. Oznacza to, że oblicza się na wartość. Możesz więc przypisać wynik całego wyrażenia case do zmiennej, jak poniżej.

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

Nie ma żadnego fall-through

Jeśli pochodzisz z innych języków, prawdopodobnie używałeś switch statement lub czegoś podobnego, i zauważyłeś, że case nie używa słów kluczowych, takich jak break, aby przerwać przepływ.

To dlatego, że nie ma żadnego fall-through z case. Po prostu zwraca wartość wyrażenia, które zostało dopasowane i to wszystko.

Wielokrotne dopasowania

Do tej pory używałeś tylko jednej wartości dla klauzuli when. Ale możesz użyć wielu wartości.

case awhen 1..3 "Small number"end

Dopasowywanie regexów

Możesz użyć wyrażeń case do dopasowania czegokolwiek. Ale na wszelki wypadek, gdyby to nie było oczywiste, możesz również dopasować regexy, lub lambdy. Oto przykład.

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

Zdefiniuj swoje własne

Jednym z mniej znanych faktów jest to, że możesz zdefiniować swoje własne komparatory.

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

W powyższym przykładzie, jeśli a jest ciągiem o długości większej niż 100 znaków, to wyrażenie case zwróci It's text.

Użyj zamiast tego polimorfizmu

Nie będę się tutaj zagłębiał w zalety OOP, więcej na ten temat możesz przeczytać w artykule Programowanie obiektowe w Ruby, ale pokażę Ci jak możesz użyć polimorfizmu do zastąpienia wyrażenia case.

Wersja case

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

Wersja 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

Dobrym pomysłem jest usunięcie jak najwięcej kodu kontroli przepływu (i.e. ifs, oraz case wyrażenia) jak to tylko możliwe. Poprawia to przestrzeganie zasady pojedynczej odpowiedzialności i ogólnie czyni program bardziej czytelnym.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *