This one just came up: How do I break out of an if
statement? I have a long if statement, but there is one situation where I can break out of it early on.
In a loop I can do this:
while (something ) {
last if $some_condition;
blah, blah, blah
...
}
However, can I do the same with an if statement?
if ( some_condition ) {
blah, blah, blah
last if $some_other_condition; # No need to continue...
blah, blah, blah
...
}
I know I could put the if
statement inside a block, and then I can break out of the block:
{
if ( some_condition ) {
...
last if $some_other_condition; # No need to continue...
blah, blah, blah
...
}
}
Or, I can create a subroutine (which is probably better programmatically):
if ( some_condition ) {
run_subroutine();
}
sub run_subroutine {
blah, blah, blah
return if $some_other_condition;
blah, blah, blah
...
}
But is there any way to exit an if
condition?
Resolution
The question came up because I was helping someone with their code. Inside a fairly long if
statement, there were several other if
statements embedded in it. The code looked something like this:
if ( $condition1 ) {
blah, blah, blah;
if ( not $condition2 ) {
blah, blah, blah;
if ( not $condition3 ) {
blah, blah, blah;
}
}
}
I thought the whole thing could be made more readable by doing this:
if ( $condition1 ) {
last if $condition2;
blah, blah, blah;
last if $condition3;
blah, blah, blah;
}
This shows that the normal flow of the if
statement is standard, but under certain conditions, the if
statement was exited early -- much like using last
or next
in a while
or for
loop to exit the loop.
I liked mpapec's solution of using a label -- even if I don't use the label itself. The label is a description of my if
:
IF-UNDER-CONDITION1:
{
if ( $condition1 ) {
last if $condition2;
blah, blah, blah;
last if $condition3;
blah, blah, blah;
}
}
Although it isn't a standard coding technique, the flow of the code is obvious enough that a typical low-level Perl developer (the one that has to maintain this code after I leave) could figure out what the code is doing and maintain it. They may even learn something in the process.
You can use basic block which is subject to last
, next
and redo
, so there is possible break from it.
if ($condition) {EXIT_IF:{
last EXIT_IF; # break from code block
print "never get's executed\n";
}}
EXIT_IF: {
if ($condition) {
last EXIT_IF; # break from code block
print "never get's executed\n";
}
}
Put it inside an empty
for()
loop, and addlast;
everywhere you want to break out AND after theif
. A bit ugly but works. Make sure to add comments to explain the trick.for (;;) { if (condition) { #code last if another_condition; } last; }
use
goto
and label a statement after your loop for that goto. Be forever damned.Extra block inside the
if
(e.g.if () {{ code }}
). May be hard to read for novices but OK if accompanied by a comment.your own solution: block around
if
. Not very obvious readability-wise.your own solution: subroutine with return.
Frankly, unless the cost of calling a sub matters performane wise, this is the cleanest solution as far as readability.
You could put the rest of your if
block inside another if
statement, like this:
if (some_condition) {
blah, blah, blah
if (!$some_other_condition) {
blah, blah, blah
...
}
}
Another alternative is to use an anonymous subroutine.
Note: I don't recommend this method because of the added scoping complexity (see note below); it is just for completeness of possible answers.
if( $true_condition ){
(sub{
return if $true_condition;
...
})->();
}
Note: any variables declared w/in the routine must use our
instead of my
if you wish to use them in the rest of the code.
I tend to use sequential if-statements based on a "do I continue?" variable instead. Your
if ( $condition1 ) {
blah, blah, blah;
if ( not $condition2 ) {
blah, blah, blah;
if ( not $condition3 ) {
blah, blah, blah;
}
}
}
can be rearranged to
my $ok = $condition1;
if ($ok) {
blah, blah, blah;
$ok = not $condition2;
}
if ($ok) {
blah, blah, blah;
$ok = not $condition3;
}
if ($ok) {
blah, blah, blah;
}
Keep your while
loop so you can use last
but also make sure that the loop is executed at most once
my $loop_once = 1;
while ( $loop_once-- and some_condition ) {
blah, blah, blah
last if $some_other_condition; # No need to continue...
blah, blah, blah
...
}
I was inspired by DVK's answer to play around, and I came up with this variant that works at least on Perl 5.26.1:
for( ; some_condition ; last ) {
blah, blah, blah
last if $some_other_condition; # No need to continue...
blah, blah, blah
}
Per perlsyn
, this is equivalent to:
while (some_condition) {
blah, blah, blah
last if $some_other_condition; # No need to continue...
blah, blah, blah
} continue {
last;
}
In a continue
block, last
has the same effect as if it had been executed in the main loop. Therefore, the loop will execute zero or one times, depending on some_condition
.
Tests
perl -E 'my ($cond, $other)=(X, Y);
for(;$cond;last) { say "hello"; last if $other; say "goodbye" }'
has the following results, for various X
and Y
values:
X Y Prints
-----------------------
0 0 (nothing)
0 1 (nothing)
1 0 hello, goodbye
1 1 hello
来源:https://stackoverflow.com/questions/17053666/perl-breaking-out-of-an-if-statement