Przesłanka
Poniższy kod należy uznać za zły format, niezależnie od języka lub pożądanej funkcjonalności:
while( true ) {
}
Argumenty wspierające
while( true )
Pętla jest słaba postać ponieważ:
- Przerywa domniemany kontrakt pętli while.
- Deklaracja pętli while powinna jawnie określać jedyny warunek wyjścia.
- Sugeruje, że zapętla się w nieskończoność.
- Aby zrozumieć klauzulę kończącą, należy odczytać kod w pętli.
- Pętle, które powtarzają się w nieskończoność, uniemożliwiają użytkownikowi zakończenie programu z poziomu programu.
- Jest nieefektywny.
- Istnieje wiele warunków zakończenia pętli, w tym sprawdzanie wartości „prawda”.
- Jest podatny na błędy.
- Nie można łatwo określić, gdzie umieścić kod, który będzie zawsze wykonywany dla każdej iteracji.
- Prowadzi do niepotrzebnie złożonego kodu.
- Automatyczna analiza kodu źródłowego.
- W celu znalezienia błędów, analizy złożoności programu, kontroli bezpieczeństwa lub automatycznego wyprowadzenia dowolnego innego zachowania kodu źródłowego bez wykonywania kodu, określenie początkowych warunków zerwania umożliwia algorytmom określenie przydatnych niezmienników, poprawiając w ten sposób wskaźniki automatycznej analizy kodu źródłowego.
- Nieskończone pętle.
- Jeśli wszyscy zawsze używają
while(true)
pętli, które nie są nieskończone, tracimy zdolność do zwięzłego komunikowania się, gdy pętle w rzeczywistości nie mają warunku zakończenia. (Prawdopodobnie to już się stało, więc kwestia jest dyskusyjna.)
Alternatywa dla „Idź do”
Poniższy kod jest lepszą formą:
while( isValidState() ) {
execute();
}
bool isValidState() {
return msg->state != DONE;
}
Zalety
Bez flagi. Nie goto
. Bez wyjątku. Łatwe do zmiany. Łatwe do odczytania. Łatwe do naprawienia. Dodatkowo kod:
- Izoluje wiedzę o obciążeniu pętli od samej pętli.
- Pozwala osobie obsługującej kod na łatwe rozszerzenie funkcjonalności.
- Umożliwia przypisanie wielu warunków zakończenia w jednym miejscu.
- Oddziela klauzulę kończącą od kodu do wykonania.
- Jest bezpieczniejszy dla elektrowni jądrowych. ;-)
Druga kwestia jest ważna. Nie wiedząc, jak działa kod, gdyby ktoś poprosił mnie o zrobienie głównej pętli, aby inne wątki (lub procesy) miały trochę czasu procesora, przychodzą mi na myśl dwa rozwiązania:
Opcja 1
Łatwo wstaw pauzę:
while( isValidState() ) {
execute();
sleep();
}
Opcja 2
Zastąp wykonaj:
void execute() {
super->execute();
sleep();
}
Ten kod jest prostszy (dzięki temu łatwiejszy do odczytania) niż pętla z osadzonym switch
. isValidState
Metoda powinna określić tylko wtedy, gdy pętla powinna kontynuować. Koń roboczy metody powinien zostać wyabstrahowany do execute
metody, co umożliwia podklasom przesłonięcie domyślnego zachowania (trudne zadanie przy użyciu osadzonych switch
i goto
).
Przykład Pythona
Porównaj następującą odpowiedź (na pytanie w Pythonie), która została opublikowana w StackOverflow:
- Pętla na zawsze.
- Poproś użytkownika o wprowadzenie swojego wyboru.
- Jeśli wprowadzeniem użytkownika jest „restart”, kontynuuj pętlę w nieskończoność.
- W przeciwnym razie przestań na zawsze zapętlić.
- Koniec.
Kod
while True:
choice = raw_input('What do you want? ')
if choice == 'restart':
continue
else:
break
print 'Break!'
Przeciw:
- Zainicjuj wybór użytkownika.
- Pętla, podczas gdy wybór użytkownika to słowo „restart”.
- Poproś użytkownika o wprowadzenie swojego wyboru.
- Koniec.
Kod
choice = 'restart';
while choice == 'restart':
choice = raw_input('What do you want? ')
print 'Break!'
Tutaj while True
skutkuje wprowadzającym w błąd i zbyt złożonym kodem.