2009-09-28 14 views
7

To wydaje się absurdalnie proste pytanie, które należy zadać, ale jaki jest najkrótszy/najbardziej idiomatyczny sposób przepisywania tego w Ruby?Jaki jest najkrótszy/najbardziej idiomatyczny sposób określania, czy zmienna jest jedną z listy wartości?

if variable == :a or variable == :b or variable == :c or variable == :d # etc. 

widziałem tego rozwiązania:

if [:a, :b, :c, :d].include? variable 

ale nie zawsze jest to funkcjonalny odpowiednik - Wierzę Array#include? faktycznie sprawdza, czy zmienna obiekt jest umieszczony w wykazie; nie bierze pod uwagę, że obiekt może wdrożyć własny test równości z def ==(other).

Jak zauważyli pomocni komentatorzy poniżej, wyjaśnienie to jest nieprawidłowe. include? używa ==, ale używa metody == elementów w tablicy. W moim przykładzie chodzi raczej o symbole, niż o metodę zmiennej. To wyjaśnia, dlaczego nie jest to równoważne z moim pierwszym przykładem kodu.

(Weźmy, na przykład, Mime::Type realizacja szyn: request.format == :html może powrócić prawda, ale [:html].include?(request.format) zwróci false, jak request.format jest instancją Pantomimy :: typ, a nie symboli.)

Najlepszym Mam do tej pory jest:

if [:a, :b, :c, :d].select {|f| variable == f}.any? 

, ale wydaje się nieco uciążliwe dla mnie. Czy ktoś ma lepsze sugestie?

+0

myślę, że „Każdy” składnia wydaje się dość czyste. Ale jestem C# i tt sorta odzwierciedla, jak wygląda LINQ, więc jestem stronniczy. –

+0

Dokumentacja stwierdza: Array # include? Zwraca wartość true, jeśli dany obiekt jest obecny w self (to znaczy, jeśli dowolny obiekt == anObject), w przeciwnym razie false. – khelll

+0

Zastanawiam się, czy zaimplementowanie metody isOneOf? (Array) w klasie Object nie jest uważane za dobrą praktykę w Ruby, mam na myśli, rozmyślanie z klasami podstawowymi (oczywiście, nie mam doświadczenia z rubinem) ... w każdym razie, byłoby w porządku, jeśli ktoś może opublikować taką metodę ... – opensas

Odpowiedz

15

Faktycznie, #include?ma używać ==. Problem polega na tym, że jeśli nie

[:a].include? foo 

sprawdza :a == foo nie foo == :a. Oznacza to, że używa metody == zdefiniowanej dla obiektów w Tablicy, a nie zmiennej. Dlatego możesz go używać, o ile upewnisz się, że obiekty w tablicy mają właściwą metodę.

W przypadkach, które nie będą działać, można uprościć swoje oświadczenie przez usunięcie komunikatu select i minięciu bloku bezpośrednio do any:

if [:a, :b, :c, :d].any? {|f| variable == f} 
+0

Aha! Myślę, że przybiłeś moje #include? problem - dziękuję, to ma sens. Powrót do problemu, podoba mi się również twoja metoda przekazywania bloku do dowolnego? - to dla mnie wygląda bardzo czysto. – NeilS

1

Zawsze używałam twojego drugiego przykładu, if [:a, :b, :c, :d].include? variable. Chociaż to powoduje pewne problemy z klasami, które nadpisują ==, w większości sytuacji, w których go potrzebowałem, jest to doskonałe rozwiązanie (zwykle sprawdzanie przed symbolami).

+0

Dzięki za komentarze. Dostałem dzisiaj ukąszenie przez [: html,: xml] .include? (Request.format), zawsze zwracając fałsz w aplikacji Rails, więc pomyślałem, że może potrzebuję wydostać się z tego nawyku! – NeilS

+2

Być może mógłbyś napisać: [: html,: xml] .include? (Request.format.to_sym) ' –

1

Jak o:

if [:a, :b, :c, :d].index variable 
+0

Dzięki za komentarz, to jest doceniane. Wydaje mi się, że wykazuje to samo zachowanie co #include ?, prawdopodobnie z tego samego powodu, który Pesto wyjaśnia w swoim komentarzu. – NeilS

0

Jakie są naprawdę robi się sprawdzając, czy zmienna jest członkiem zestawu [:a,:b,:c,:d] tak semantycznie że odwzorowuje metody include?.

Problem wystąpić ze względu na charakter kaczego typowanie Ruby, więc jeśli chcesz, aby ominąć to dlaczego nie najpierw przekonwertować do symbolu:

if [:a, :b, :c, :d].include? variable.to_sym 
+0

Dzięki za komentarz, to jest doceniane. To działa w wielu przypadkach, ale oczywiście nie zadziała, jeśli dany obiekt implementuje dalszą logikę w swojej definicji równości. (Być może porównuje to także z listą synonimów, na przykład.) – NeilS

3

Wygląda Array#include? nie wykorzystać ==:

>> class AString < String 
>> def ==(other) 
>>  self[0] == other[0] 
>> end 
>> end 

>> asdf = AString.new "asdfg" 
=> "asdfg" 
>> b = AString.new 'aer' 
=> "aer" 

>> asdf == b 
=> true 

>> [asdf].include? b 
=> true 

Dokumentacja Array#include? również wyjaśnia to.

+0

Dzięki za twoją analizę; to jest doceniane. Zostałem oszukany przez problem, który Pesto zauważa powyżej, stąd moje zamieszanie. – NeilS

Powiązane problemy