2015-06-30 7 views
8

(Poprosiłem to pytanie już at Ruby Forum, ale nie wyciągnął żadnej odpowiedzi, więc jestem Wysyłasz go teraz)Ruby: target-less „przypadek”, w porównaniu do „if”

Od Rozumiem, następujące fragmenty kodu są równoważne pod Ruby 1.9 i nowszy:

# (1) 
case 
when x < y 
    foo 
when a > b 
    bar 
else 
    baz 
end 

# (2) 
if x < y 
    foo 
elsif a > b 
    bar 
else 
    baz 
end 

dotychczas bym zawsze używany (2), z przyzwyczajenia. Czy ktoś mógłby pomyśleć: z konkretnego powodu, dlaczego (1) lub (2) jest "lepszy", czy jest to tylko kwestia gustu?

WYJAŚNIENIE: Niektórzy użytkownicy wyrazili zastrzeżenia, że ​​to pytanie byłoby po prostu "oparte na opiniach", a zatem nie pasowało do tego forum. Dlatego uważam, że nie przedstawiłem się wystarczająco jasno: nie chcę rozpoczynać dyskusji na temat osobistego stylu programowania. Powód dla którego poruszyłem ten temat jest następujący:

Zaskoczyło mnie, że Ruby oferuje dwie bardzo różne składnie (bezcelową i if-elsif), ponieważ wydaje mi się, że to dokładnie ten sam cel, w szczególności, ponieważ składnia if-elsif jest tą, którą praktycznie każdy programista zna. Nie uważałbym nawet "bezcelowego za" jako "cukier syntaktyczny", ponieważ nie pozwala mi to wyrazić logiki programowania bardziej konsekwentnie niż "if-elsif".

Zastanawiam się, w jakiej sytuacji mógłbym chcieć użyć konstruktu "pozbawionego celu". Czy daje przewagę wydajności? Czy różni się od if-elsif w subtelny sposób, którego po prostu nie zauważam?

DODATKOWE ustaleń dotyczących realizacji docelowego mniej przypadku:

Olivier Poulin wskazał, że cel mniej case byłoby jawnie użyć operatora === wobec wartości „true”, co spowodowałoby (malutka) kara za "przypadek" w porównaniu do "jeśli" (i jeszcze jeden powód, dla którego nie widzę powodu, dla którego ktoś mógłby chcieć go użyć).

Jednak podczas sprawdzania dokumentacji oświadczenia o przypadkach dla Ruby 1.9 i Ruby 2.0, stwierdziłem, że opisują to inaczej, ale obie co najmniej sugerują, że === NIE może być używane w tym przypadku. W przypadku Ruby 1.9:

stwierdzenia przypadków składają się z opcjonalnego stanu, który jest w pozycji argument do wypadku i zero lub więcej, gdy klauzul. Pierwszy, gdy klauzula dopasować warunek (lub ocenę do logicznej prawdy, jeśli warunek jest null) „wygrywa”

Tu jest napisane, że jeśli warunek (czyli to, co przychodzi po „wypadku”) jest null (tj. nie istnieje), pierwsza klauzula "when", która jest prawdziwa, to ta, która jest wykonywana. Brak odniesienia do === tutaj.

W Ruby 2.0 sformułowanie jest zupełnie inna:

Sprawa wyrażenie może być używany na dwa sposoby. Najpopularniejszym sposobem jest porównywanie obiektu z wieloma wzorcami. Wzory są dopasowywane za pomocą metody + === + [.....]. Innym sposobem użycia wyrażenia case jest jak wyrażenie if-elsif: [przykład przypadku bez celu jest podany tutaj].

Dlatego mówi, że === jest używane w "pierwszy" sposób (przypadek z celem), natomiast przypadek bez celu "jest jak" if-elsif.Tutaj nie ma wzmianki o ===.

+2

++ za zadeklarowanie przekupu. – 7stud

Odpowiedz

6

Midwire zabrakło kilku punktów odniesienia i stwierdził, że jeśli/elsif jest szybszy niż przypadku, ponieważ przypadek „niejawnie porównuje używając droższej === operatora”.

jest tam, gdzie mam ten cytat. Porównuje on oświadczenia if/elsif do case.

Jest bardzo dokładny i analizuje różnice w sekwencji instrukcji, zdecydowanie da Ci pomysł, który jest lepszy.

Najważniejszą rzeczą, jaką wyciągnąłem z tego postu, jest to, że zarówno jeśli, jak i inaczej, nie ma dużych różnic , obydwa mogą być zwykle używane zamiennie.

Niektóre główne różnice mogą się pojawić w zależności od tego, ile masz przypadków.

n = 1 (last clause matches) 
if:   7.4821e-07 
threequal_if: 1.6830500000000001e-06 
case:   3.9176999999999997e-07 

n = 15 (first clause matches) 
if:   3.7357000000000003e-07 
threequal_if: 5.0263e-07 
case:   4.3348e-07 

Jak widać, jeśli ostatni punkt jest dopasowany, if/elsif biegnie znacznie wolniej niż przypadku, gdy if pierwsza klauzula jest dopasowany, to na odwrót.

Różnica ta wynika z faktu, że if/elsif używa branchunless, natomiast case wykorzystuje branchif w ich sekwencji instrukcji.


Oto test zrobiłem na własną rękę z tarczą mniej case vs if/elsif sprawozdania (za pomocą "=="). Pierwszy raz to case, natomiast po raz drugi to if/elsif.

Pierwszy test, 5 when instrukcji, 5 if/elsif, pierwsza klauzula jest prawdziwa dla obu.

Time elapsed 0.052023 milliseconds                                                                                                  
Time elapsed 0.031467999999999996 milliseconds 

Drugie badanie, 5 when oświadczenia, 5 if/elsif, ostatni (5) klauzula jest prawdziwe dla obu stron.

Time elapsed 0.001224 milliseconds                                                                                                 
Time elapsed 0.028578 milliseconds 

Jak widać, tak jak widzieliśmy wcześniej, kiedy pierwsza klauzula jest prawdziwe, jeśli/elsif wykonać lepiej niż przypadku, gdy sprawa ma masywny przewagę wydajności, gdy ostatnia klauzula jest prawdą.

WNIOSEK

przebiegu dalsze badania wykazały, że prawdopodobnie sprowadza się do prawdopodobieństwa. Jeśli uważasz, że odpowiedź pojawi się wcześniej na liście klauzul, użyj if/elsif, inaczej case wydaje się być szybszy.

Najważniejsze, że to pokazało, że zarówno case, jak i if/elsif są równie wydajne i że użycie jednego z nich sprowadza się do prawdopodobieństwa i smaku.

+0

Zawsze uważałem, że 'case' jest szybszy w porównaniu do wartości statycznych i' if' przy stosowaniu arbitralnej logiki. – tadman

+0

@tadman, czy możesz podać mi przykład? –

+0

Formularz 'case (x)' działa bardzo dobrze w porównaniu z "przypadkiem" otwartym bez argumentów. W benchmarkach znalazłem 'case (x)' vs. wartości statyczne, takie jak '2' lub' "2" 'może przewyższać wyszukiwanie hasłem. Im więcej masz warunków, tym wolniejszy jest odpowiednik jednego z nich. – tadman

Powiązane problemy