Kto zdecydował (i na podstawie jakich pojęć), że switch
konstrukcja (w wielu językach) musi być użyta break
w każdym stwierdzeniu?
Dlaczego musimy napisać coś takiego:
switch(a)
{
case 1:
result = 'one';
break;
case 2:
result = 'two';
break;
default:
result = 'not determined';
break;
}
(zauważyłem to w PHP i JS; prawdopodobnie używa wielu innych języków)
Jeśli switch
jest to alternatywa if
, dlaczego nie możemy użyć tej samej konstrukcji, co dla if
? To znaczy:
switch(a)
{
case 1:
{
result = 'one';
}
case 2:
{
result = 'two';
}
default:
{
result = 'not determined';
}
}
Mówi się, że break
uniemożliwia wykonanie bloku następującego po bieżącym. Ale czy ktoś naprawdę wpadł na sytuację, w której istniała potrzeba wykonania bieżącego bloku i kolejnych? Ja nie. Dla mnie break
zawsze tam jest. W każdym bloku. W każdym kodzie.
conditions
trejder
źródło
źródło
CASE
instrukcję równorzędnie z gigantycznym blokiem if / elseif.case 'a': case 'A': case 'b': case 'B'
ale głównie dlatego, że nie mogęcase in [ 'a', 'A', 'b', 'B' ]
. Nieco lepszym pytaniem jest, w moim obecnym preferowanym języku (C #), przerwa jest obowiązkowa i nie ma żadnego ukrytego upadku; zapominaniebreak
jest błędem składni ...: \case TOKEN_A: /*set flag*/; case TOKEN_B: /*consume token*/; break; case TOKEN_C: /*...*/
break
jest obecny w dowolnym miejscu” jest znacznie prostszą zasadą do wdrożenia niż „Nie wysyłaj skoku, jeślifallthrough
jest obecny wswitch
”.Odpowiedzi:
C był jednym z pierwszych języków, w którym
switch
oświadczenie było w tej formie, i wszystkie inne główne języki odziedziczyły je stamtąd, przeważnie decydując się zachować domyślną semantykę C - albo nie zastanawiały się nad zaletami jego zmiany, albo osądzały mniej ważne niż zachowanie, do którego wszyscy byli przyzwyczajeni.Co do tego, dlaczego C został zaprojektowany w ten sposób, prawdopodobnie wynika on z koncepcji C jako „przenośnego zestawu”.
switch
Stwierdzenie jest w zasadzie poboru tabeli oddziału i stół oddział ma również niejawna jesieni-through i wymaga dodatkowej instrukcji skoku, aby tego uniknąć.Zasadniczo projektanci C również postanowili zachować semantykę asemblera jako domyślną.
źródło
switchon
.when
.Ponieważ
switch
nie jest alternatywą dlaif ... else
oświadczeń w tych językach.Używając
switch
, możemy dopasować więcej niż jeden warunek na raz, co jest bardzo cenione w niektórych przypadkach.Przykład:
źródło
more than one block ... unwanted in most cases
Nie zgadzam się z tobą.break
. Ale tak, o ile mi wiadomo, urządzenie Duffa nie działa w języku C #.C# does not support an implicit fall through from one case label to another
. Możesz wpaść, ale nie ma szans przypadkowo zapomnieć o przerwie.if..else
ale w niektórych sytuacjachswitch..case
byłoby lepiej. Powyższy przykład byłby nieco skomplikowany, gdybyśmy użyli if-else.To pytanie zostało zadane w przypadku przepełnienia stosu w kontekście C: Dlaczego instrukcja switch została zaprojektowana tak, aby wymagała przerwy?
Podsumowując przyjętą odpowiedź, prawdopodobnie był to błąd. Większość innych języków prawdopodobnie właśnie zastosowało się do C. Jednak niektóre języki, takie jak C #, wydają się naprawiać to, pozwalając na awarię - ale tylko wtedy, gdy programista wyraźnie to mówi (źródło: link powyżej, nie mówię w języku C #) .
źródło
/* FALLTHRU */
komentarz w odpowiedzi pod linkiem @Tapio powyżej, aby udowodnić , że miałeś na myśli.goto case
, podobnie jak link, nie ilustruje, dlaczego to działa tak dobrze. Nadal możesz układać w stos wiele przypadków, jak wyżej, ale jak tylko wstawisz kod, musisz mieć wyraźny wyraz,goto case whatever
aby przejść do następnej sprawy lub otrzymasz błąd kompilatora. Jeśli o mnie zapytacie, umiejętność układania spraw bez martwienia się o nieumyślne przejście przez zaniedbanie jest zdecydowanie lepszą cechą niż umożliwienie jawnego rozwiązaniagoto case
.Odpowiem przykładem. Jeśli chcesz podać liczbę dni dla każdego miesiąca w roku, oczywiste jest, że niektóre miesiące mają 31, około 30 i 1 28/29. Tak by wyglądało
Jest to przykład, w którym wiele przypadków ma ten sam efekt i wszystkie są zgrupowane razem. Istniał oczywiście powód wyboru słowa kluczowego break, a nie argumentu if ... else if construct.
Najważniejszą rzeczą do odnotowania tutaj jest to, że instrukcja switch z wieloma podobnymi przypadkami nie jest jeśli… jeśli… jeśli… jeśli… jeśli… w każdym przypadku, ale jeśli (1, 2, 3) ... inaczej jeśli (4,5,6) jeszcze ...
źródło
if
bez żadnych korzyści. Być może, jeśli twój przykład nadałby nazwę lub pracował nad konkretnym miesiącem oprócz upadku, użyteczność upadku byłaby bardziej widoczna? (bez komentowania, czy POWINIEN być na pierwszym miejscu)Istnieją dwie sytuacje, w których może wystąpić „wpadnięcie” z jednej skrzynki do drugiej - pusta skrzynka:
i niepusty pojemnik
Niezależnie od odniesienia do Urządzenia Duffa , uzasadnione przypadki dla drugiego przypadku są nieliczne i daleko od nich, i generalnie są zabronione przez standardy kodowania i oznaczone podczas analizy statycznej. A tam, gdzie to jest znalezione, jest to najczęściej spowodowane pominięciem litery
break
.Ten pierwszy jest całkowicie rozsądny i powszechny.
Szczerze mówiąc, nie widzę powodu, dla którego potrzebuję
break
parsera i języka, wiedząc, że puste ciało-sprawa to upadek, podczas gdy niepuste pudełko jest samodzielne.Szkoda, że panel ISO C wydaje się bardziej zajęty dodawaniem do języka nowych (niechcianych) i źle zdefiniowanych funkcji, niż naprawianiem nieokreślonych, nieokreślonych lub zdefiniowanych przez implementację funkcji, nie wspominając o nielogiczności.
źródło
Brak wymuszania
break
dopuszcza wielu rzeczy, które w innym przypadku mogłyby być trudne. Inni zauważyli przypadki grupowania, dla których istnieje szereg spraw niebanalnych.Jednym z przypadków, w których konieczne
break
jest nieużywanie, jest Urządzenie Duffa . Służy do „ rozwijania ” pętli, w których może przyspieszyć operacje, ograniczając liczbę wymaganych porównań. Wierzę, że początkowe użycie pozwoliło na funkcjonalność, która wcześniej była zbyt wolna z całkowicie zwiniętą pętlą. W niektórych przypadkach zamienia rozmiar kodu na szybkość.Dobrą praktyką jest zastąpienie
break
odpowiedniego komentarzem, jeśli sprawa ma jakiś kod. W przeciwnym razie ktoś naprawi brakujące narzędziebreak
i wprowadzi błąd.źródło
W C, gdzie wydaje się, że początek, blok kodu
switch
instrukcji nie jest specjalną konstrukcją. Jest to normalny blok kodu, podobnie jak blok podif
instrukcją.case
idefault
przeskakują etykiety wewnątrz tego bloku, szczególnie związane zswitch
. Są obsługiwane tak jak normalne etykiety skokugoto
. Ważna jest tutaj jedna konkretna zasada: etykiety skoków mogą znajdować się prawie wszędzie w kodzie, bez zakłócania przepływu kodu.Jako zwykły blok kodu nie musi to być instrukcja złożona. Etykiety są również opcjonalne. Są to ważne
switch
oświadczenia w katalogu C:Sam standard C podaje to jako przykład (6.8.4.2):
Co więcej,
default
jest również etykietą skoku, a zatem może być w dowolnym miejscu, bez potrzeby bycia ostatnim przypadkiem.To wyjaśnia również urządzenie Duffa:
Skąd ta awaria? Ponieważ w normalnym przepływie kodu w normalnym bloku kodu oczekuje się przejścia do następnej instrukcji , tak jak można tego oczekiwać w
if
bloku kodu.Domyślam się, że powodem tego była łatwość wdrożenia. Nie potrzebujesz specjalnego kodu do parsowania i kompilowania
switch
bloku, dbając o specjalne reguły. Po prostu parsujesz go jak każdy inny kod i musisz tylko dbać o etykiety i wybór skoku.Ciekawym pytaniem uzupełniającym z tego wszystkiego jest to, czy następujące zagnieżdżone instrukcje wypisują „Gotowe”. albo nie.
Norma C dba o to (6.8.4.2.4):
źródło
Kilka osób wspomniało już o dopasowaniu wielu warunków, co jest bardzo cenne od czasu do czasu. Jednak zdolność dopasowania wielu warunków niekoniecznie wymaga, abyś robił dokładnie to samo z każdym pasującym warunkiem. Rozważ następujące:
Istnieją dwa różne sposoby dopasowania zestawów wielu warunków. W przypadku warunków 1 i 2 po prostu przechodzą do dokładnie tego samego wykresu kodu i robią dokładnie to samo. Jednak z warunkami 3 i 4, mimo że oba kończą się połączeniem
doSomething3And4()
, tylko 3 połączeniadoSomething3()
.źródło
case 2
, więc jeśli chcemy być poprawni (i robimy) prawdziwe nazwa funkcji musiałaby byćdoSomethingBecause_1_OR_2_OR_1AND2()
lub coś takiego (chociaż poprawny kod, w którym niezmienny pasuje do dwóch różnych przypadków, a mimo to dobrze napisany kod, praktycznie nie istnieje, więc przynajmniej tak powinno byćdoSomethingBecause1or2()
)doSomething[ThatShouldBeDoneInTheCaseOf]1And[InTheCaseOf]2()
. Nie odnosi się to do logiki i / lub.Aby odpowiedzieć na dwa twoje pytania.
Dlaczego C potrzebuje przerw?
Sprowadza się do korzeni Cs jako „przenośnego asemblera”. Gdzie taki kod psudo był powszechny: -
instrukcja switch została zaprojektowana w celu zapewnienia podobnej funkcjonalności na wyższym poziomie.
Czy kiedykolwiek mamy przełączniki bez przerw?
Tak, jest to dość powszechne i istnieje kilka przypadków użycia;
Po pierwsze, możesz chcieć podjąć to samo działanie w kilku przypadkach. Robimy to, układając skrzynki jedna na drugiej:
Innym przypadkiem użycia powszechnym w automatach stanów jest to, że po przetworzeniu jednego stanu natychmiast chcemy wprowadzić i przetworzyć inny stan:
źródło
Instrukcja break jest instrukcją skokową, która pozwala użytkownikowi wyjść z najbliższego załączającego przełącznika (w twoim przypadku), podczas gdy, do, for lub foreach. to takie proste.
źródło
Myślę, że przy wszystkich powyższych tekstach - głównym rezultatem tego wątku jest to, że jeśli chcesz zaprojektować nowy język - domyślnie powinno być tak, że nie musisz dodawać
break
instrukcji, a kompilator potraktuje to tak, jakbyś to zrobił.Jeśli chcesz ten rzadki przypadek, w którym chcesz przejść do następnej sprawy - po prostu podaj
continue
oświadczenie.Można to poprawić, tak że tylko jeśli użyjesz nawiasów klamrowych wewnątrz obudowy, nie będzie to kontynuowane, więc przykład z powyższymi miesiącami kilku przypadków wykonujących ten sam dokładny kod - zawsze działałby zgodnie z oczekiwaniami bez potrzeby
continue
.źródło
*
,&
,static
itp