2014-09-12 10 views
7

Ich habe ein Programm mit einer while-Schleife, die mehrere Punkte hat, wo bestimmte Bedingungen erfordern, dass etwas unternommen wird und dann der Rest der Iteration übersprungen wird.Beenden einer Iteration einer Schleife aus einer Subroutine

Da dies immer der gleiche Code sein wird, wollte ich es in eine Unterroutine einfügen, aber wenn ich 'next;' Als letzte Anweisung in der Subroutine erhalte ich eine Warnung (Subroutine wird durch next at ... beendet), obwohl es so zu funktionieren scheint wie beabsichtigt.

d.h. ohne sub:

while (#condition) { 

    ## do stuff 

    if (#condition to skip iteration) { 
     ## action 
     next; 
    } 

    ## do more stuff, with the above block repeated several times 
} 

mit sub:

while (#condition) { 

    ## do stuff 

    &skip if (#condition to skip iteration); 

    ## do more stuff, with more calls to &skip 
} 

sub skip() { 
    ## action 
    next; 
} 

Der Rest des Codes in dem Block/sub ist so kurz, dass alle bis auf den nächsten setzen; Die Anweisung in einem Unterprogramm vereitelt ziemlich das Objekt der Verwendung eines Unterprogramms.

Meine Frage ist:

  • Ist mit 'next;' in einem Unterprogramm auf diese Weise in Ordnung, oder ist es gefährlich/schlechte Praxis?
  • Gibt es eine bessere Möglichkeit, den Rest der Iteration von einer Subroutine zu überspringen?
  • Wenn es in Ordnung ist und es keinen besseren Weg gibt, gibt es eine Möglichkeit, die Warnung zu unterdrücken?

Antwort

4

Ihr Warninstinkt ist wahrscheinlich richtig. Wie Sie sagen, next ist einfach nicht die Art von Anweisung, die man in ein Unterprogramm einbettet. Auch wenn Sie es nicht vorziehen, ist dies mit ziemlicher Sicherheit besser:

while (#condition) { 

    ## do stuff 

    &skip, next if (#condition to skip iteration); 

    ## do more stuff, with more calls to &skip 
} 

sub skip() { 
    ## action 
} 

(ich eine ziemlich entspannte Haltung gegenüber Nicht-Standard-Programmiertechniken haben passieren, vor allem, wenn sie nicht überstrapaziert sind, wenn Sie stark fühlen über die next Einbettung. In diesem Fall werde ich nicht mit Ihnen streiten, da es Ihr Programm ist, aber trotzdem, da Sie um Rat gefragt haben, stimme ich Ihrem Instinkt zu, dass die Einbettung der next wahrscheinlich keine gute Idee ist.)

+0

Warum verwenden Sie die runden Klammern beim Unterspringen? Keine Notwendigkeit, Prototyping oder Signaturen hier zu verwenden. Vielleicht weniger verwirrend, sie zu entfernen. – jmmeier

3

Warnungen warnen nicht, wenn dies eine gute Übung ist. Verwenden Sie Ihre Funktion, so dass sie früh statt next zurückgibt. Sie können für die Funktion Ergebnis überprüfen und entscheiden, ob sie nächste Iteration zu überspringen, oder überspringen bedingungslos zur nächsten,

use warnings; 

sub foo { 
    print ($_, "\n"); 
} 

for (1..10) { 
    foo(), next if $_ %2;; 
} 
6

Vom Perl 6. Auflage Seite 179 (Fußnote)

Lernen Es ist wahrscheinlich nicht eine gute Idee, aber Sie könnten diese Schleifensteuerung Operatoren aus einer Unterroutine verwenden, um eine Schleife zu steuern, die sich außerhalb der Unterroutine befindet. Das heißt, wenn ein Unterprogramm in einem Schleifenblock aufgerufen wird und das Unterprogramm zuletzt ausgeführt wird, wenn innerhalb des Unterprogramms kein Schleifenblock läuft, springt der Ablauf der Steuerung direkt nach dem Schleifenblock im Hauptcode. Diese Möglichkeit, die Schleifensteuerung von innerhalb einer Subroutine zu verwenden, kann in einer zukünftigen Version von Perl, und verschwinden.

könnte die Lösung sein, was andere schon gesagt, oder Sie können wie

use strict; 
use warnings; 

while(<>) { 
    chomp; 
    maybeskip($_) && next if m/2/; #maybe skip if match 2 
    print "$_\n"; 
} 

sub maybeskip { 
    $_[0] !~ m/0/; #skip only if not match 0 
    # the sub retuns the result of the last executed expression 
    # if this is not wanted you should use explicit return $value; 
} 

für die

seq 25 | perl script 

druckt im sub, zusätzlichen Test tun:

1 
3 
4 
5 
6 
7 
8 
9 
10 
11 
13 
14 
15 
16 
17 
18 
19 
20 

z übersprungen alle 2 aber nicht 20

8

Es ist einfach, die Warnung zu unterdrücken. Legen Sie einfach die folgende Zeile über die next:

no warnings "exiting"; 

Die Warnung ist es für einen Grund - next in einem Helferunter mit wie das für die nächste Person verwirrend sein kann, die den Code lesen hat (wer sind Sie in 6 Monaten!), weil die next nicht lexikalisch innerhalb des Schleifenblocks auftritt. Wenn Sie nur den Schleifenblock lesen, bemerken Sie möglicherweise nicht, dass next weiter unten in der Datei; und wenn Sie nur die Definition des Unterprogramms lesen, können Sie nicht sicher sein, was das next ist. Sie müssen beide Teile des Codes zusammen lesen, um einen Sinn daraus zu ziehen. Das macht es verwirrender als next direkt in der Schleife zu verwenden.

Außerdem begrenzt es die Wiederverwendbarkeit des zuvor definierten skip()-Subs. Möchten Sie das skip() Sub innerhalb einer anderen Schleife wiederverwenden? Sie sollten besser hoffen, dass die Skip-Logik in der neuen Schleife noch Sinn ergibt.

Wenn Sie all dies in Betracht gezogen haben und trotzdem fortfahren möchten, deaktivieren Sie einfach die Warnung, wie oben gezeigt. Warnungen sind keine Fehler, sie sind nur Warnungen. Deshalb werden Warnungen als "Warnungen" bezeichnet. Sie sind darauf ausgelegt, Ihre Aufmerksamkeit auf etwas zu lenken potenziell problematisch; dich nicht davon abzuhalten, etwas zu tun, von dem du dich entschieden hast, ist nützlich.

3

Sie können einen Teil/die gesamte Überspringbedingung in das Unterprogramm einfügen, indem Sie truthy auf next zurücksetzen und mit dem Operator and fortfahren.