A BLOCK
by itself (labeled
or not) is semantically equivalent to a loop that executes once. Thus
you can use last
to leave the block or
redo
to restart the block.[4] Note that this is not true of the blocks in
eval {}
, sub {}
, or, much to
everyone's surprise, do {}
. These three are not
loop blocks because they're not BLOCK
s by
themselves; the keyword in front makes them mere terms in an
expression that just happen to include a code block. Since they're not
loop blocks, they cannot be given a label to apply loop controls to.
Loop controls may only be used on true loops, just as a
return
may only be used within a subroutine (well,
or an eval
).
Loop controls don't work in an if
or
unless
, either, since those aren't loops. But you
can always introduce an extra set of braces to give yourself a bare
block, which does count as a loop:
if (/pattern/) {{ last if /alpha/; last if /beta/; last if /gamma/; # do something here only if still in if() }}
Here's how a block can be used to let loop-control operators
work with a do{}
construct. To
next
or redo
a
do
, put a bare block inside:
do {{ next if $x == $y; # do something here }} until $x++ > $z;
For last
, you have to be more
elaborate:
{ do { last if $x = $y ** 2; # do something here } while $x++ <= $z; }
And if you want both loop controls available, you'll have put a label on those blocks so you can tell them apart:
DO_LAST: { do { DO_NEXT: { next DO_NEXT if $x == $y; last DO_LAST if $x = $y ** 2; # do something here } } while $x++ <= $z; }
But certainly by that point (if not before), you'd be better off
using an ordinary infinite loop with last
at the
end:
for (;;) { next if $x == $y; last if $x = $y ** 2; # do something here last unless $x++ <= $z; }
Unlike some other programming languages, Perl has no
official switch
or case
statement. That's because Perl doesn't need one, having many ways to
do the same thing. A bare block is particularly convenient for doing
case structures (multiway switches). Here's
one:
SWITCH: { if (/^abc/) { $abc = 1; last SWITCH; } if (/^def/) { $def = 1; last SWITCH; } if (/^xyz/) { $xyz = 1; last SWITCH; } $nothing = 1; }
and here's another:
SWITCH: { /^abc/ && do { $abc = 1; last SWITCH; }; /^def/ && do { $def = 1; last SWITCH; }; /^xyz/ && do { $xyz = 1; last SWITCH; }; $nothing = 1; }
or, formatted so that each case stands out more:
SWITCH: { /^abc/ && do { $abc = 1; last SWITCH; }; /^def/ && do { $def = 1; last SWITCH; }; /^xyz/ && do { $xyz = 1; last SWITCH; }; $nothing = 1; }
or even (horrors!):
if (/^abc/) { $abc = 1 } elsif (/^def/) { $def = 1 } elsif (/^xyz/) { $xyz = 1 } else { $nothing = 1 }
In this next example, notice how the
last
operators ignore the do
{}
blocks, which aren't loops, and exit the
for
loop instead:
for ($very_nasty_long_name[$i++][$j++]->method()) { /this pattern/ and do { push @flags, '-e'; last; }; /that one/ and do { push @flags, '-h'; last; }; /something else/ and do { last; }; die "unknown value: `$_'"; }
You might think it odd to loop over a single value,
since you'll only go through the loop once. But it's convenient to
use for
/foreach
's aliasing
capability to make a temporary, localized assignment to
$_
. On repeated compares against the same long
value, this makes it much easier to type and therefore harder to
mistype. It avoids possible side effects from evaluating the
expression again. And pertinent to this section, it's also one of
the most commonly seen standard idioms for implementing a switch or
case structure.
Cascading use of the ?
: operator
can also work for simple cases. Here we again use a
for
for its aliasing property to make repeated
comparisons more legible:
for ($user_color_preference) { $value = /red/ ? 0xFF0000 : /green/ ? 0x00FF00 : /blue/ ? 0x0000FF : 0x000000 ; # black if all fail }
For situations like this last one, it's sometimes better to build yourself a hash and quickly index into it to pull the answer out. Unlike the cascading conditionals we just looked at, a hash scales to an unlimited number of entries, and takes no more time to look up the first one than the last. The disadvantage is that you can only do an exact lookup, not a pattern match. If you have a hash like this:
%color_map = ( azure => 0xF0FFFF, chartreuse => 0x7FFF00, lavender => 0xE6E6FA, magenta => 0xFF00FF, turquoise => 0x40E0D0, );
then exact string lookups run quickly:
$value = $color_map{ lc $user_color_preference } || 0x000000;
Even complicated multiway branching statements (with each case involving the execution of several different statements) can be turned into fast lookups. You just need to use a hash of references to functions. See Section 9.5 in Chapter 9, for how to handle those.
[4] For reasons that may (or may not) become clear upon
reflection, a next
also exits the once-through
block. There is a slight difference, however: a
next
will execute a continue
block, but a last
won't.
Get Programming Perl, 3rd Edition now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.