📄 ch04_05.htm
字号:
<html><head><title>Bare Blocks (Programming Perl)</title><!-- STYLESHEET --><link rel="stylesheet" type="text/css" href="../style/style1.css"><!-- METADATA --><!--Dublin Core Metadata--><meta name="DC.Creator" content=""><meta name="DC.Date" content=""><meta name="DC.Format" content="text/xml" scheme="MIME"><meta name="DC.Generator" content="XSLT stylesheet, xt by James Clark"><meta name="DC.Identifier" content=""><meta name="DC.Language" content="en-US"><meta name="DC.Publisher" content="O'Reilly & Associates, Inc."><meta name="DC.Source" content="" scheme="ISBN"><meta name="DC.Subject.Keyword" content=""><meta name="DC.Title" content="Bare Blocks"><meta name="DC.Type" content="Text.Monograph"></head><body><!-- START OF BODY --><!-- TOP BANNER --><img src="gifs/smbanner.gif" usemap="#banner-map" border="0" alt="Book Home"><map name="banner-map"><AREA SHAPE="RECT" COORDS="0,0,466,71" HREF="index.htm" ALT="Programming Perl"><AREA SHAPE="RECT" COORDS="467,0,514,18" HREF="jobjects/fsearch.htm" ALT="Search this book"></map><!-- TOP NAV BAR --><div class="navbar"><table width="515" border="0"><tr><td align="left" valign="top" width="172"><a href="ch04_04.htm"><img src="../gifs/txtpreva.gif" alt="Previous" border="0"></a></td><td align="center" valign="top" width="171"><a href="ch04_01.htm">Chapter 4: Statements and Declarations</a></td><td align="right" valign="top" width="172"><a href="ch04_06.htm"><img src="../gifs/txtnexta.gif" alt="Next" border="0"></a></td></tr></table></div><hr width="515" align="left"><!-- SECTION BODY --><h2 class="sect1">4.5. Bare Blocks</h2><a name="INDEX-1134"></a><a name="INDEX-1135"></a><p><a name="INDEX-1136"></a><a name="INDEX-1137"></a><a name="INDEX-1138"></a><a name="INDEX-1139"></a><a name="INDEX-1140"></a>A <em class="replaceable">BLOCK</em> by itself (labeled or not) issemantically equivalent to a loop that executes once. Thus you canuse <tt class="literal">last</tt> to leave the block or<tt class="literal">redo</tt> to restart the block.<a href="#FOOTNOTE-4">[4]</a> Note that this is not true of the blocks in<tt class="literal">eval {}</tt>, <tt class="literal">sub {}</tt>, or, much toeveryone's surprise, <tt class="literal">do {}</tt>. These three are notloop blocks because they're not <em class="replaceable">BLOCK</em>s bythemselves; the keyword in front makes them mere terms in anexpression that just happen to include a code block. Since they'renot loop blocks, they cannot be given a label to apply loop controlsto. Loop controls may only be used on true loops, just as a<tt class="literal">return</tt> may only be used within a subroutine (well,or an <tt class="literal">eval</tt>).</p><blockquote class="footnote"><a name="FOOTNOTE-4"></a><p>[4] Forreasons that may (or may not) become clear upon reflection, a<tt class="literal">next</tt> also exits the once-through block. There is aslight difference, however: a <tt class="literal">next</tt> will execute a<tt class="literal">continue</tt> block, but a <tt class="literal">last</tt>won't.</p></blockquote><p><a name="INDEX-1141"></a><a name="INDEX-1142"></a>Loop controls don't work in an <tt class="literal">if</tt> or <tt class="literal">unless</tt>, either, sincethose aren't loops. But you can always introduce an extra set ofbraces to give yourself a bare block, which <em class="emphasis">does</em> count as a loop:<blockquote><pre class="programlisting">if (/pattern/) {{ last if /alpha/; last if /beta/; last if /gamma/; # do something here only if still in if()}}</pre></blockquote><a name="INDEX-1143"></a><a name="INDEX-1144"></a></p><p>Here's how a block can be used to let loop-control operators work witha <tt class="literal">do{}</tt> construct. To <tt class="literal">next</tt> or <tt class="literal">redo</tt> a <tt class="literal">do</tt>, put a bare blockinside:<blockquote><pre class="programlisting">do {{ next if $x == $y; # do something here}} until $x++ > $z;</pre></blockquote><a name="INDEX-1145"></a><a name="INDEX-1146"></a></p><p>For <tt class="literal">last</tt>, you have to be more elaborate:<blockquote><pre class="programlisting">{ do { last if $x = $y ** 2; # do something here } while $x++ <= $z;}</pre></blockquote>And if you want both loop controls available, you'll have put a labelon those blocks so you can tell them apart:<blockquote><pre class="programlisting">DO_LAST: { do {DO_NEXT: { next DO_NEXT if $x == $y; last DO_LAST if $x = $y ** 2; # do something here } } while $x++ <= $z; }</pre></blockquote>But certainly by that point (if not before), you'd be better off usingan ordinary infinite loop with <tt class="literal">last</tt> at the end:<blockquote><pre class="programlisting">for (;;) { next if $x == $y; last if $x = $y ** 2; # do something here last unless $x++ <= $z;}</pre></blockquote></p><h3 class="sect2">4.5.1. Case Structures</h3><a name="INDEX-1147"></a><a name="INDEX-1148"></a><a name="INDEX-1149"></a><a name="INDEX-1150"></a><a name="INDEX-1151"></a><p>Unlike some other programming languages, Perl has no official <tt class="literal">switch</tt> or <tt class="literal">case</tt> statement. That's because Perldoesn't need one, having many ways to do the same thing. A bare blockis particularly convenient for doing case structures (multiwayswitches). Here's one:<blockquote><pre class="programlisting">SWITCH: { if (/^abc/) { $abc = 1; last SWITCH; } if (/^def/) { $def = 1; last SWITCH; } if (/^xyz/) { $xyz = 1; last SWITCH; } $nothing = 1;}</pre></blockquote>and here's another:<blockquote><pre class="programlisting">SWITCH: { /^abc/ && do { $abc = 1; last SWITCH; }; /^def/ && do { $def = 1; last SWITCH; }; /^xyz/ && do { $xyz = 1; last SWITCH; }; $nothing = 1;}</pre></blockquote>or, formatted so that each case stands out more:<blockquote><pre class="programlisting">SWITCH: { /^abc/ && do { $abc = 1; last SWITCH; }; /^def/ && do { $def = 1; last SWITCH; }; /^xyz/ && do { $xyz = 1; last SWITCH; }; $nothing = 1;}</pre></blockquote>or even (horrors!):<blockquote><pre class="programlisting">if (/^abc/) { $abc = 1 }elsif (/^def/) { $def = 1 }elsif (/^xyz/) { $xyz = 1 }else { $nothing = 1 }</pre></blockquote><a name="INDEX-1152"></a>In this next example, notice how the <tt class="literal">last</tt> operators ignore the <tt class="literal">do{}</tt> blocks, which aren't loops, and exit the <tt class="literal">for</tt> loop instead:<blockquote><pre class="programlisting">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: `$_'";}</pre></blockquote><a name="INDEX-1153"></a><a name="INDEX-1154"></a>You might think it odd to loop over a single value, since you'll onlygo through the loop once. But it's convenient to use <tt class="literal">for</tt>/<tt class="literal">foreach</tt>'saliasing capability to make a temporary, localized assignment to<tt class="literal">$_</tt>. On repeated compares against the same long value, this makes itmuch easier to type and therefore harder to mistype. It avoidspossible side effects from evaluating the expression again. Andpertinent to this section, it's also one of the most commonly seenstandard idioms for implementing a switch or case structure.</p><p><a name="INDEX-1155"></a><a name="INDEX-1156"></a><a name="INDEX-1157"></a>Cascading use of the <tt class="literal">?:</tt> operator can also work for simplecases. Here we again use a <tt class="literal">for</tt> for its aliasing propertyto make repeated comparisons more legible:<blockquote><pre class="programlisting">for ($user_color_preference) { $value = /red/ ? 0xFF0000 : /green/ ? 0x00FF00 : /blue/ ? 0x0000FF : 0x000000 ; # black if all fail}</pre></blockquote><a name="INDEX-1158"></a>For situations like this last one, it's sometimes better to buildyourself a hash and quickly index into it to pull the answer out.Unlike the cascading conditionals we just looked at, a hash scales toan unlimited number of entries, and takes no more time to look up thefirst one than the last. The disadvantage is that you can only do anexact lookup, not a pattern match. If you have a hash like this:<blockquote><pre class="programlisting">%color_map = ( azure => 0xF0FFFF, chartreuse => 0x7FFF00, lavender => 0xE6E6FA, magenta => 0xFF00FF, turquoise => 0x40E0D0,);</pre></blockquote>then exact string lookups run quickly:<blockquote><pre class="programlisting">$value = $color_map{ lc $user_color_preference } || 0x000000;</pre></blockquote>Even complicated multiway branching statements (with each caseinvolving the execution of several different statements) can be turnedinto fast lookups. You just need to use a hash of references tofunctions. See the section <a href="ch09_05.htm#ch09-sect-hof">Section 4.5, "Hashes of Functions"</a> in <a href="ch09_01.htm">Chapter 9, "Data Structures"</a>, for how to handle those.</p><a name="INDEX-1159"></a><a name="INDEX-1160"></a><!-- BOTTOM NAV BAR --><hr width="515" align="left"><div class="navbar"><table width="515" border="0"><tr><td align="left" valign="top" width="172"><a href="ch04_04.htm"><img src="../gifs/txtpreva.gif" alt="Previous" border="0"></a></td><td align="center" valign="top" width="171"><a href="index.htm"><img src="../gifs/txthome.gif" alt="Home" border="0"></a></td><td align="right" valign="top" width="172"><a href="ch04_06.htm"><img src="../gifs/txtnexta.gif" alt="Next" border="0"></a></td></tr><tr><td align="left" valign="top" width="172">4.4. Loop Statements</td><td align="center" valign="top" width="171"><a href="index/index.htm"><img src="../gifs/index.gif" alt="Book Index" border="0"></a></td><td align="right" valign="top" width="172">4.6. goto</td></tr></table></div><hr width="515" align="left"><!-- LIBRARY NAV BAR --><img src="../gifs/smnavbar.gif" usemap="#library-map" border="0" alt="Library Navigation Links"><p><font size="-1"><a href="copyrght.htm">Copyright © 2001</a> O'Reilly & Associates. All rights reserved.</font></p><map name="library-map"> <area shape="rect" coords="2,-1,79,99" href="../index.htm"><area shape="rect" coords="84,1,157,108" href="../perlnut/index.htm"><area shape="rect" coords="162,2,248,125" href="../prog/index.htm"><area shape="rect" coords="253,2,326,130" href="../advprog/index.htm"><area shape="rect" coords="332,1,407,112" href="../cookbook/index.htm"><area shape="rect" coords="414,2,523,103" href="../sysadmin/index.htm"></map><!-- END OF BODY --></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -