Czy pętle „while (true)” są tak złe? [Zamknięte]

218

Programuję w Javie od kilku lat, ale niedawno wróciłem do szkoły, aby uzyskać formalny stopień naukowy. Byłem bardzo zaskoczony, gdy dowiedziałem się, że podczas ostatniego zadania straciłem punkty za użycie pętli takiej jak ta poniżej.

do{
     //get some input.
     //if the input meets my conditions, break;
     //Otherwise ask again.
} while(true)

Teraz do testu szukam tylko danych wejściowych konsoli, ale powiedziano mi, że tego rodzaju pętla jest odradzana, ponieważ używanie breakjest podobne goto, po prostu tego nie robimy.

Rozumiem w pełni pułapki gotoi kuzyna Javy break:labeli mam zdrowy rozsądek, aby z nich nie korzystać. Zdaję sobie również sprawę, że bardziej kompletny program zapewniłby inne sposoby ucieczki, powiedzmy na przykład, aby po prostu zakończyć program, ale to nie był powód, o którym wspomniał mój profesor, więc ...

Co jest nie tak z do-while(true)?

JHarnach
źródło
23
Zapytaj swojego nauczyciela, że ​​tego rodzaju rzeczy są dość subiektywne.
Chris Eberle
18
Uważam, że ten artykuł pomaga zrozumieć, co jest szkodliwe w goto . Porównanie z breakprawdopodobnie ma sens, ale w rzeczywistości jest źle zrozumiane. Być może możesz wyszkolić swojego profesora na ten temat;) Z mojego doświadczenia wynika, że ​​profesorowie niewiele wiedzą o rzemiośle programowania.
Magnus Hoff,
100
Jedyną naprawdę niepodważalną złą rzeczą jest to, że do {} while (true)jest to równoważne, while(true) {}a ta ostatnia jest zdecydowanie bardziej konwencjonalna i znacznie bardziej przejrzysta.
Voo,
11
Jeśli ktoś nie docenia prostej ekspresyjnej mocy break, powinien spróbować programować w języku bez niego. Nie potrzeba zbyt wielu pętli, zanim będziesz tego chciał!
Steven
16
Nie zgadzam się z tagiem pracy domowej.
aaaa bbbb

Odpowiedzi:

220

Nie powiedziałbym, że to źle - ale normalnie szukałbym przynajmniej alternatywy.

W sytuacjach, w których to pierwsza rzecz, którą piszę, prawie zawsze przynajmniej staram się przekształcić to w coś bardziej przejrzystego. Czasami nic nie można na to poradzić (lub alternatywnie jest mieć boolzmienną, która nie robi nic znaczącego poza wskazaniem końca pętli, mniej wyraźnie niż breakinstrukcja), ale warto przynajmniej spróbować.

Jako przykład tego, gdzie łatwiej jest używać breakniż flagę, rozważ:

while (true)
{
    doStuffNeededAtStartOfLoop();
    int input = getSomeInput();
    if (testCondition(input))
    {
        break;
    }
    actOnInput(input);
}

Teraz zmusimy go do użycia flagi:

boolean running = true;
while (running)
{
    doStuffNeededAtStartOfLoop();
    int input = getSomeInput();
    if (testCondition(input))
    {
        running = false;
    }
    else
    {
        actOnInput(input);
    }
}

Uważam, że ten ostatni jest bardziej skomplikowany do czytania: ma dodatkowy elseblok, actOnInputjest bardziej wcięty, a jeśli próbujesz dowiedzieć się, co się stanie, gdy testConditionpowróci true, musisz uważnie przejrzeć resztę bloku, aby sprawdzić, czy tam jest nie jest to coś po tym elsebloku, które mogłyby wystąpić, czy runningzostał ustawiony falselub nie.

To breakoświadczenie komunikuje intencję jaśniej i pozwala pozostałej części bloku zająć się tym, co musi zrobić, nie martwiąc się o wcześniejsze warunki.

Zauważ, że jest to dokładnie ten sam argument, który ludzie mają na temat wielu instrukcji return w metodzie. Na przykład, jeśli potrafię wypracować wynik metody w pierwszych kilku wierszach (np. Ponieważ niektóre dane wejściowe są puste, puste lub zerowe), łatwiej jest zwrócić tę odpowiedź bezpośrednio niż mieć zmienną do przechowywania wyniku , a następnie cały blok z innym kodem, i wreszciereturn stwierdzenie.

Jon Skeet
źródło
3
Zgadzam się, że nie jest to pierwsze narzędzie, do którego sięgnęłam, ale wydawało się, że rozwiązało problem tak czysto i lubię czysty kod.
JHarnach
3
@ X-Zero: Tak, czasami. Jeśli potrafisz przekształcić „zerwanie” w „powrót”, to często jest to dobroć ... chociaż nadal możesz skończyć zwhile (true)
Jon Skeet
21
@trutheality: Wolę, aby większość mojego kodu była jak najbardziej niezauważalna. A stan z przypisaniem złożonym jest dla mnie bardziej skomplikowany.
Jon Skeet
3
@Vince: Tak, i to świetnie, jeśli możesz łatwo wyrazić warunek na początku pętli . Ale czasami nie możesz - i o takiej sytuacji mówimy. Proszę zwrócić uwagę na kilka pierwszych zdań mojej odpowiedzi.
Jon Skeet,
6
@Ismail: Mam nadzieję, że nie. Posty powinny być oceniane wyłącznie na podstawie ich treści, a nie autora. Cholera, nawet głosowałbym za postem Erica Lipperta, gdybym poczuł, że jest on niedokładny / nieprzydatny. To się jednak jeszcze nie zdarzyło :)
Jon Skeet
100

AFAIK nic, naprawdę. Nauczyciele są po prostu uczuleni goto, ponieważ słyszeli, że gdzieś jest naprawdę źle. W przeciwnym razie po prostu napiszesz:

bool guard = true;
do
{
   getInput();
   if (something)
     guard = false;
} while (guard)

Co jest prawie takie samo.

Może to jest czystsze (ponieważ wszystkie informacje o zapętleniu znajdują się na górze bloku):

for (bool endLoop = false; !endLoop;)
{

}
El Marcel
źródło
4
Podoba mi się twoja sugestia, ponieważ warunek zakończenia jest znacznie bardziej widoczny. Oznacza to, że czytając kod, wcześniej zrozumiesz, co on próbuje zrobić. Nigdy nie używałbym nieskończonej pętli, ale często używam twoich dwóch wersji.
Sled
4
Konsensus jest taki, że flaga jest lepsza niż złamanie w dużej mierze, ponieważ wyraża zamiar? Widzę, że to jest korzystne. Wszystkie solidne odpowiedzi, ale oznaczę to jako zaakceptowane.
JHarnach
20
Oba z nich nadal cierpią z powodu zanieczyszczenia pozostałej części pętli (przynajmniej w niektórych sytuacjach) przez konieczność przechodzenia do końca korpusu pętli, nawet jeśli wiesz, że się zrywasz . Podam przykład w mojej odpowiedzi ...
Jon Skeet
8
Bardziej podoba mi się odpowiedź Jona Skeeta. Ponadto, podczas gdy (prawda) {} jest DUŻO lepszy niż zrobić {} podczas gdy (prawda)
aaaa bbbb
1
Nienawidzę tego, że Dijkstra kiedykolwiek napisał ten artykuł GoTo. Chociaż GoTo z pewnością był często nadużywany w przeszłości, nie oznacza, że ​​nigdy nie powinieneś go używać. Również Exit For, Break, Exit While, Try / Catch to tylko wyspecjalizowane formy Goto. Gotos często sprawia, że ​​kod jest bardziej czytelny. I tak, wiem, że wszystko można zrobić bez Goto. To nie znaczy, że powinno.
Kibbee
39

Douglas Crockford miał uwagę na temat tego, jak chciał, aby JavaScript zawierał loopstrukturę:

loop
{
  ...code...
}

I nie sądzę, że Java byłaby gorsza z powodu posiadania loopstruktury.

Nie ma nic złego w while(true)pętli, ale jest tendencja do nauczycieli, aby ich zniechęcić. Z punktu widzenia nauczania bardzo łatwo jest sprawić, aby uczniowie tworzyli niekończące się pętle i nie rozumieli, dlaczego pętla nigdy nie ucieka.

Ale rzadko wspominają o tym wszystkie mechanizmy zapętlania można powielać za pomocą while(true)pętli.

while( a() )
{
  fn();
}

jest taki sam jak

loop
{
  if ( !a() ) break;
  fn();
}

i

do
{
  fn();
} while( a() );

jest taki sam jak:

loop
{
  fn();
  if ( !a() ) break;
}

i

for ( a(); b(); c() )
{
  fn();
}

jest taki sam jak:

a();
loop
{
  if ( !b() ) break;
  fn();
  c();
}

Tak długo, jak możesz skonfigurować swoje pętle w sposób, który działa, konstrukcja, którą wybierzesz, jest nieistotna. Jeśli zdarzy się, że zmieści się w forpętli, użyj forpętli.

Ostatnia część: zachowaj prostotę pętli. Jeśli na każdej iteracji musi się wydarzyć wiele funkcji, umieść ją w funkcji. Zawsze możesz go zoptymalizować po uruchomieniu.

zzzzBov
źródło
2
+1: Istnieją dodatkowe zawiłości z forpętlami, gdy continuezaangażowane są instrukcje, ale nie są one poważnym rozszerzeniem.
Donal Fellows
Zwykle używam pętli for, gdy istnieje sekwencja, przez którą chcę biegać, i pętli while, gdy występuje warunek, który chcę spełnić. Dzięki temu kod jest bardziej czytelny.
dascandy
4
Czy nikt już nie pisze for (;;) {? (Wymawiane „na zawsze”). To było bardzo popularne.
Dawood ibn Kareem
16

W 1967 roku Edgar Dijkstra napisał artykuł w czasopiśmie branżowym o tym, dlaczego goto należy wyeliminować z języków wysokiego poziomu, aby poprawić jakość kodu. Wyszedł z tego cały paradygmat programowania zwany „programowaniem strukturalnym”, choć z pewnością nie wszyscy są zgodni, że goto automatycznie oznacza zły kod.

Sedno programowania strukturalnego polega zasadniczo na tym, że struktura kodu powinna określać jego przepływ, a nie mieć gotów, przerw lub kontynuować określanie przepływu, tam gdzie to możliwe. Podobnie, posiadanie wielu punktów wejścia i wyjścia do pętli lub funkcji jest również odradzane w tym paradygmacie.

Oczywiście nie jest to jedyny paradygmat programowania, ale często można go łatwo zastosować do innych paradygmatów, takich jak programowanie obiektowe (ala Java).

Twoi nauczyciele prawdopodobnie zostali nauczeni i starają się nauczyć twoją klasę, że powinniśmy unikać „kodu spaghetti”, upewniając się, że nasz kod jest ustrukturyzowany i przestrzegając dorozumianych zasad programowania strukturalnego.

Chociaż w implementacji wykorzystującej break nie ma nic „zła”, niektórzy uważają, że znacznie łatwiej jest odczytać kod, w którym warunek dla pętli jest wyraźnie określony w ramach while (), i eliminuje pewne możliwości bycia zbyt trudnym. Zdecydowanie występują pułapki związane z używaniem warunku chwilowego (prawdziwego), który wydaje się często pojawiać w kodzie przez początkujących programistów, na przykład ryzyko przypadkowego utworzenia nieskończonej pętli lub uczynienia kodu trudnym do odczytania lub niepotrzebnie mylącym.

Jak na ironię, obsługa wyjątków jest obszarem, w którym z pewnością pojawią się odstępstwa od programowania strukturalnego, których należy oczekiwać w miarę dalszego programowania w Javie.

Możliwe jest również, że instruktor spodziewał się, że zademonstrujesz swoją umiejętność korzystania z konkretnej struktury pętli lub składni nauczanej w tym rozdziale lub lekcji tekstu, a chociaż napisany kod jest funkcjonalnie równoważny, być może nie demonstrowałeś szczególne umiejętności, których miałeś się nauczyć podczas tej lekcji.

Jessica Brown
źródło
2
Oto artykuł Edsgera Dijkstry . To dobra lektura.
Roy Prins
14

Zwykła konwencja Java do odczytu danych wejściowych to:

import java.io.*;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String strLine;

while ((strLine = br.readLine()) != null) {
  // do something with the line
}

A typowa konwencja C ++ do odczytu danych wejściowych to:

#include <iostream>
#include <string>
std::string data;
while(std::readline(std::cin, data)) {
  // do something with the line
}

A w C to jest

#include <stdio.h>
char* buffer = NULL;
size_t buffer_size;
size_t size_read;
while( (size_read = getline(&buffer, &buffer_size, stdin)) != -1 ){
  // do something with the line
}
free(buffer);

lub jeśli jesteś przekonany, że wiesz, jak długa jest najdłuższa linia tekstu w pliku, możesz to zrobić

#include <stdio.h>
char buffer[BUF_SIZE];
while (fgets(buffer, BUF_SIZE, stdin)) {
  //do something with the line
}

Jeśli testujesz, czy użytkownik wprowadził quitpolecenie, łatwo rozszerzyć dowolną z 3 struktur pętli. Zrobię to dla Ciebie w Javie:

import java.io.*;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line;

while ((line = br.readLine()) != null  && !line.equals("quit") ) {
  // do something with the line
}

Tak więc, choć z pewnością istnieją przypadki, w których jest breaklub gotojest uzasadnione, jeśli wszystko, co robisz, to czytanie z pliku lub konsoli wiersz po wierszu, nie powinieneś potrzebować while (true)pętli, aby to zrobić - Twój język programowania już ci zapewnił z odpowiednim idiomem dla używania polecenia wejściowego jako warunku pętli.

Ken Bloom
źródło
W rzeczywistości, jeśli używasz while (true)pętli zamiast jednej z tych konwencjonalnych pętli wejściowych, możesz zapomnieć o sprawdzeniu końca pliku.
Ken Bloom
3
Osiągasz to skutecznie, upychając pierwszą część pętli w whilewarunkowe. W końcowym stanie Java robi się już dość mocny, a jeśli musiałbyś przeprowadzić rozległe manipulacje, aby zdecydować, czy kontynuować, czy nie, może to potrwać dość długo. Możesz podzielić go na osobną funkcję, i może być najlepiej. Ale jeśli chcesz to w jednej funkcji, a przed podjęciem decyzji o kontynuowaniu nie jest łatwa praca, while(true)być może najlepiej.
poolie
@poolie: Prawdopodobnie najlepiej użyć polecenia read jako warunku pętli (który sprawdza EOF) i sprawdzić inne warunki wewnątrz pętli jako instrukcje break.
Ken Bloom
1
Co jest warte, gets()nie jest powszechną konwencją. Bardzo sprzyja przepełnieniu bufora. fgets(buffer, BUFFER_SIZE, file)jest znacznie bardziej jak standardowa praktyka.
Dave
@Dave: Zredagowałem odpowiedź do użycia fgets.
Ken Bloom
12

To nie jest takie okropne, ale musisz wziąć pod uwagę innych programistów podczas kodowania. Nawet w szkole.

Twoi inni programiści powinni być w stanie zobaczyć klauzulę wyjścia dla pętli w deklaracji pętli. Nie zrobiłeś tego Ukryłeś klauzulę wyjścia w środku pętli, dzięki czemu więcej pracy dla kogoś, kto przychodzi i próbuje zrozumieć Twój kod. Z tego samego powodu unika się takich rzeczy jak „przerwa”.

To powiedziawszy, nadal zobaczysz takie rzeczy w wielu kodach w prawdziwym świecie.

rfeak
źródło
4
Jeśli pętla zacznie się od while (true), jest całkiem oczywiste, że będzie w niej breaklub w returnśrodku, albo że będzie działać na zawsze. Bycie bezpośrednim jest ważne, alewhile(true) samo w sobie nie jest szczególnie złe. Zmienne, które mają złożone niezmienniki w iteracjach pętli, byłyby przykładem czegoś, co powoduje znacznie więcej niepokoju.
poolie
4
Spróbuj przejść trzy poziomy głęboko w poszukiwaniu, a następnie jakoś się wydostać. Kod będzie znacznie gorszy, jeśli nie wrócisz od tego momentu.
dascandy
11

To twoja broń, twoja kula i twoja stopa ...

Jest źle, ponieważ prosisz o kłopoty. To nie ty ani żaden inny plakat na tej stronie będzie miał przykłady krótkich / prostych pętli while.

Problemy zaczną się w przyszłości w bardzo przypadkowym momencie. Może to być spowodowane przez innego programistę. Może to być osoba instalująca oprogramowanie. Może to być użytkownik końcowy.

Czemu? Musiałem dowiedzieć się, dlaczego aplikacja 700K LOC stopniowo zaczyna spalać 100% czasu procesora, aż każdy procesor zostanie nasycony. To była niesamowita pętla while (prawdziwa). Był duży i nieprzyjemny, ale sprowadzał się do:

x = read_value_from_database()
while (true) 
 if (x == 1)
  ...
  break;
 else if (x ==2)
  ...
  break;
and lots more else if conditions
}

Nie było jeszcze żadnej innej gałęzi. Jeśli wartość nie była zgodna z warunkiem if, pętla działała do końca czasu.

Oczywiście, programista obwinił użytkowników końcowych, że nie wybrali wartości, której oczekiwał. (Następnie usunąłem wszystkie wystąpienia while (true) w kodzie).

IMHO nie jest dobrym programowaniem defensywnym do używania konstrukcji takich jak while (prawda). Wróci, by cię prześladować.

(Ale przypominam sobie, że profesorowie obniżali stopnie, jeśli nie komentowaliśmy każdej linii, nawet dla i ++;)

jqa
źródło
3
+1 za komentarz na temat programowania obronnego.
JHarnach
3
W twoim przykładzie kod jest głupi nie z powodu wyboru chwili (prawda), ale z powodu pomijania pętli wokół kodu.
Florian F
Rzeczywiście, jaki był sens tej pętli? :)
juzzlin
6

Jest to złe w tym sensie, że konstrukcje programowania strukturalnego są lepsze niż (nieco nieustrukturyzowane) instrukcje break i continu. Dla porównania, zgodnie z tą zasadą preferowane są „goto”.

Zawsze zalecałbym, aby twój kod był jak najbardziej ustrukturyzowany ... chociaż, jak zauważa Jon Skeet, nie rób go bardziej strukturalnym!

Patrick87
źródło
5

Zgodnie z moim doświadczeniem w większości przypadków pętle mają warunek „główny”, aby kontynuować. Jest to warunek, w który należy zapisać sam operator while (). Wszystkie pozostałe warunki, które mogą przerwać pętlę, są drugorzędne, nie tak ważne itp. Mogą być zapisane jako dodatkowe if() {break}instrukcje.

while(true) jest często mylące i mniej czytelne.

Myślę, że zasady te nie obejmują 100% spraw, ale prawdopodobnie tylko 98% z nich.

AlexR
źródło
Dobrze powiedziane. To jest jak używanie pętli for za pomocą: while (true) {i ++; ...}. Zakopujesz stan pętli wewnątrz pętli, a nie w „sygnaturze”.
LegendLength
3

Chociaż niekoniecznie jest to odpowiedź na pytanie, dlaczego nie używać while (true), zawsze uważałem to komiczne i towarzyszące oświadczenie autora za zwięzłe wyjaśnienie, dlaczego robić to zamiast robić.

Jeśli chodzi o twoje pytanie: nie ma z tym żadnego problemu

while(true) {
   do_stuff();
   if(exit_time) {
      break;
   }
}

... jeśli wiesz, co robisz i upewniasz się, że exit_timew pewnym momencie to oceni true.

Nauczyciele zniechęcają cię do używania, while(true)ponieważ dopóki nie wiesz dokładnie, co robisz, jest to łatwy sposób na popełnienie krytycznego błędu.

Shadur
źródło
Myślę, że ustawienie exit_time = false; while(!exit_time) { execute_stuff(); }i do { execute_stuff(); } while(! exit_time );oba są znacznie wyraźniejsze niż posiadanie if( condition ) { break; }na końcu pętli za pomocą while(true). Przerwy są zwarciem do pętli - idealnie w porządku, gdy są używane jako zwarcie w środku pętli, ale powinieneś po prostu ocenić stan w instrukcji while i mieć przerwę na końcu pętli.
dr jimbob
W odniesieniu do tego komiksu: podczas gdy robienie-nie może zrobić wszystkiego, co może robić, robienie-czasem czasem lepiej robić to, co może robić, nawet gdy może to robić.
Theraot
3

Możesz po prostu użyć flagi boolowskiej, aby wskazać, kiedy zakończyć pętlę while. Breaki go tobyły powody, dla których oprogramowanie jest trudne w utrzymaniu - kryzys oprogramowania (tm) - i należy go unikać, i łatwo może być również.

To pytanie, czy jesteś pragmatyczny, czy nie. Pragmatyczni koderzy mogą po prostu użyć przerwy w tej prostej sytuacji.

Ale dobrze jest przyzwyczaić się do ich nieużywania, w przeciwnym razie możesz użyć ich z przyzwyczajenia w nieodpowiednich sytuacjach, na przykład w skomplikowanych pętlach zagnieżdżonych, w których korzystanie z kodu staje się trudniejsze do odczytania i utrzymania break.

Daniel Leschkowski
źródło
8
Ponieważ utrzymywanie flagi logicznej prawdopodobnie nie jest jaśniejsze, a moim zdaniem może być mniej jasne?
Jon Skeet
3
@Jon Skeet Cóż, chodzi o to, aby iść z dobrym nawykiem lub ćwiczyć się źle, używając przerwy. Bool zwany „bieganiem” nie jest dla ciebie jasny? Jest oczywisty, łatwy do debugowania, a jak już wspomniałem, dobry nawyk jest dobrym rozwiązaniem. Gdzie jest problem?
Daniel Leschkowski
4
Bool o nazwie run, który wymaga ode mnie if (running)pętli, wcięcia całej reszty kodu, kiedy wszystko, czego chcę, to wyjście z pętli, jest dla mnie zdecydowanie mniej zrozumiałe niż prosta instrukcja break, która mówi dokładnie, co chcę zrobić. Wydaje ci się, że rozważasz używanie przerwy jako złego nawyku aksjomatycznego - nie uważam tego za takie.
Jon Skeet
2
Dlaczego miałbyś mieć if (działający) w pętli? Podobnie jak w przypadku break na końcu pętli sprawdzasz, czy chcesz się wybić i odwrócić flagę zamiast używać break i użyj flagi w while (bieg) zamiast while (prawda). Naprawdę nie rozumiem o co ci chodzi. Zgodziłbym się, że pragmatyczny programista może użyć przerwy w pewnych sytuacjach, ale tak naprawdę nie otrzymuję komentarzy, które
napisałeś
3
Zakładasz, że nie musisz nic robić w pętli po ustaleniu, czy chcesz wyjść. Na przykład w sytuacji PO musi poprosić o więcej informacji, jeśli nie zrezygnuje.
Jon Skeet
3

Może mam pecha. A może po prostu brakuje mi doświadczenia. Ale za każdym razem Pamiętam czynienia z while(true)konieczności breakw środku, można było poprawić kod stosowania Extract Method do while-bloku , który zachował while(true)jednak (przez przypadek?) Przekształca wszystkie breaks językreturn s.

Z mojego doświadczenia while(true)wynika, że ​​bez przerw (tj. Ze zwrotami lub rzutami) są dość wygodne i łatwe do zrozumienia.


  void handleInput() {
      while (true) {
          final Input input = getSomeInput();
          if (input == null) {
              throw new BadInputException("can't handle null input");
          }
          if (input.isPoisonPill()) {
              return;
          }
          doSomething(input);
      }
  }
komar
źródło
3

Myślę, że tak, to jest całkiem złe ... a przynajmniej dla wielu programistów. Jest to symptomatyczne dla programistów, którzy nie myślą o swoich warunkach pętli. W konsekwencji występuje podatność na błędy.

Griff Sob Becker
źródło
2

Nie ma poważny problem while(true)zbreak sprawozdaniem, jednak niektórzy mogą pomyśleć jego nieznacznie zmniejsza czytelność kodu. Staraj się nadawać zmiennym znaczące nazwy, oceniaj wyrażenia we właściwym miejscu.

Na przykład, wydaje się o wiele łatwiej zrobić coś takiego:

do {
   input = get_input();
   valid = check_input_validity(input);    
} while(! valid)

Jest to szczególnie ważne, jeśli pętla do while jest długa - dokładnie wiesz, gdzie sprawdza się, czy występuje dodatkowa iteracja. Wszystkie zmienne / funkcje mają odpowiednie nazwy na poziomie abstrakcji. Thewhile(true)Oświadczenie nie jest powiedzieć, że przetwarzanie nie jest na miejscu, można myśleć.

Być może za drugim razem chcesz uzyskać inne wyjście. Coś jak

input = get_input();
while(input_is_not_valid(input)) {
    disp_msg_invalid_input();
    input = get_input();
}

wydaje mi się wtedy bardziej czytelny

do {
    input = get_input();
    if (input_is_valid(input)) {
        break;
    }
    disp_msg_invalid_input();
} while(true);

Ponownie, w trywialnym przykładzie oba są dość czytelne; ale jeśli pętla stała się bardzo duża lub głęboko zagnieżdżona (co oznacza, że ​​prawdopodobnie powinieneś już była zrestrukturyzowana), pierwszy styl może być nieco wyraźniejszy.

dr jimbob
źródło
1

Używam czegoś podobnego, ale z przeciwną logiką, w wielu moich funkcjach.

DWORD dwError = ERROR_SUCCESS;

do
{
    if ( (dwError = SomeFunction()) != ERROR_SUCCESS )
    {
         /* handle error */
         continue;
    }

    if ( (dwError = SomeOtherFunction()) != ERROR_SUCCESS )
    {
         /* handle error */
         continue;
    }
}
while ( 0 );

if ( dwError != ERROR_SUCCESS )
{
    /* resource cleanup */
}
Jim Fell
źródło
1

Jest to bardziej kwestia estetyki, dużo łatwiejszy do odczytania kod, w którym wyraźnie wiesz, dlaczego pętla zatrzyma się w deklaracji pętli.

Petey B.
źródło
1

Powiedziałbym, że ogólnie powodem, dla którego nie jest uważany za dobry pomysł, jest to, że nie używasz konstruktu do pełnego potencjału. Poza tym myślę, że wielu instruktorom programowania nie podoba się to, gdy ich uczniowie przychodzą z „bagażem”. Rozumiem przez to, że uważam, że lubią oni mieć główny wpływ na styl programowania swoich uczniów. Więc może to tylko zwierzę domowe wkurza instruktora.

Paweł
źródło
1

Dla mnie problemem jest czytelność.

Instrukcja while z prawdziwym warunkiem nie mówi nic o pętli. To znacznie utrudnia zrozumienie go.

Co byłoby łatwiejsze do zrozumienia z tych dwóch fragmentów?

do {
  // Imagine a nice chunk of code here
} while(true);

do {
  // Imagine a nice chunk of code here
} while(price < priceAllowedForDiscount);
Vince Panuccio
źródło
0

Myślę, że użycie przerwy dla nauczyciela jest jak złamanie gałęzi drzewa, aby zdobyć owoc, użyj innych sztuczek (pochyl gałąź), aby uzyskać owoc, a gałąź wciąż żyje :)

Bimal Sharma
źródło
0

1) Nic nie jest nie tak z do -while(true)

2) Twój nauczyciel się myli.

NSFS !!:

3) Większość nauczycieli to nauczyciele, a nie programiści.

Pacerier
źródło
@ Connell poczekaj, aż twój nauczyciel to usłyszy!
Pacerier
1
Jestem samoukiem w dziedzinie programowania. Jedyne, co muszę oceniać, to mój nauczyciel informatyki w szkole średniej, który nauczył nas robić strony internetowe przy użyciu Dreamweaver w taki sposób, że WSZYSTKO było absolutnie pozycjonowaną dywizją ...
Connell
@ Połącz mój post, aby pokazać swoją zgodę
Pacerier
2
„Ci, którzy nie mogą, nauczaj”. - To dość duże uogólnienie, nie sądzisz? Czy lekarze, inżynierowie, piloci itp. Powinni być samoukami, ponieważ ich instruktorzy są według ciebie niekompetentni?
filip-fku
@ filip-fku wow wow ~ cool it cool it!
Pacerier
0

Może być źle, jeśli pętla działa w wątku w tle, więc po zamknięciu aplikacji przez zakończenie wątku interfejsu użytkownika ten fragment kodu będzie nadal wykonywany. Jak już powiedzieli inni, zawsze powinieneś użyć pewnego rodzaju czeku, aby zapewnić sposób na anulowanie.

Dmitry
źródło