?? ch24_04.htm
字號:
<html><head><title>Fluent Perl (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="Fluent Perl"><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="ch24_03.htm"><img src="../gifs/txtpreva.gif" alt="Previous" border="0"></a></td><td align="center" valign="top" width="171"><a href="ch24_01.htm">Chapter 24: Common Practices</a></td><td align="right" valign="top" width="172"><a href="ch24_05.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">24.4. Fluent Perl</h2><p><a name="INDEX-4278"></a><a name="INDEX-4279"></a><a name="INDEX-4280"></a>We've touched on a few idioms in the preceding sections (not to mentionthe preceding chapters), but there are many other idioms you'llcommonly see if you read programs by accomplished Perl programmers.When we speak of idiomatic Perl in this context, we don't just mean aset of arbitrary Perl expressions with fossilized meanings.Rather, we mean Perl code that shows an understanding of the flow ofthe language, what you can get away with when, and what that buysyou. And when to buy it.</p><p>We can't hope to list all the idioms you might see--that would take abook as big as this one. Maybe two. (See the <em class="emphasis">PerlCookbook</em>, for instance.) But here are some of theimportant idioms, where "important" might be defined as "that whichinduces hissy fits in people who think they already know just howcomputer languages ought to work".</p><ul><li><p>Use <tt class="literal">=></tt> in place of a comma anywhere you think it improves readability:<blockquote><pre class="programlisting">return bless $mess => $class;</pre></blockquote>This reads, "Bless this mess into the specified class." Just be carefulnot to use it after a word that you don't want autoquoted:<blockquote><pre class="programlisting">sub foo () { "FOO" }sub bar () { "BAR" }print foo => bar; # prints fooBAR, not FOOBAR;</pre></blockquote>Another good place to use <tt class="literal">=></tt> is near a literalcomma that might get confused visually:<blockquote><pre class="programlisting">join(", " => @array);</pre></blockquote>Perl provides you with more than one way to do things so that you canexercise your ability to be creative. Exercise it!</p></li><li><p>Use the singular pronoun to increase readability:<blockquote><pre class="programlisting">for (@lines) { $_ .= "\n";}</pre></blockquote>The <tt class="literal">$_</tt> variable is Perl's version of a pronoun, and it essentiallymeans "it". So the code above means "for each line, append a newline to<em class="emphasis">it</em>." Nowadays you might even spell that:<blockquote><pre class="programlisting">$_ .= "\n" for @lines;</pre></blockquote>The <tt class="literal">$_</tt> pronoun is so important to Perl that its useis mandatory in <tt class="literal">grep</tt> and <tt class="literal">map</tt>.Here is one way to set up a cache of common results of an expensivefunction:<blockquote><pre class="programlisting">%cache = map { $_ => expensive($_) } @common_args;$xval = $cache{$x} || expensive($x);</pre></blockquote></p></li><li><p>Omit the pronoun to increase readability even further.<a href="#FOOTNOTE-1">[1]</a></p><blockquote class="footnote"><a name="FOOTNOTE-1"></a><p>[1]In this section, multiple bullet items in a row all refer to the subsequent example, since some of our examples illustrate more than one idiom.</p></blockquote></li><li><p>Use loop controls with statement modifiers.<blockquote><pre class="programlisting">while (<>) { next if /^=for\s+(index|later)/; $chars += length; $words += split; $lines += y/\n//;}</pre></blockquote>This is a fragment of code we used to do page counts for this book. Whenyou're going to be doing a lot of work with the same variable, it'soften more readable to leave out the pronouns entirely, contrary tocommon belief.</p><p>The fragment also demonstrates the idiomatic use of <tt class="literal">next</tt>with a statement modifier to short-circuit a loop.</p><p>The <tt class="literal">$_</tt> variable is always the loop control variablein <tt class="literal">grep</tt> and <tt class="literal">map</tt>, but theprogram's reference to it is often implicit:<blockquote><pre class="programlisting">@haslen = grep { length } @random;</pre></blockquote>Here we take a list of random scalars and only pick the ones that havea length greater than <tt class="literal">0</tt>.</p></li><li><p>Use <tt class="literal">for</tt> to set the antecedent for a pronoun:<blockquote><pre class="programlisting">for ($episode) { s/fred/barney/g; s/wilma/betty/g; s/pebbles/bambam/g;}</pre></blockquote>So what if there's only one element in the loop? It's a convenientway to set up "it", that is, <tt class="literal">$_</tt>. Linguistically, this is knownas topicalization. It's not cheating, it's communicating.</p></li><li><p>Implicitly reference the plural pronoun, <tt class="literal">@_</tt>.</p></li><li><p>Use control flow operators to set defaults:<blockquote><pre class="programlisting">sub bark { my Dog $spot = shift; my $quality = shift || "yapping"; my $quantity = shift || "nonstop"; ...}</pre></blockquote>Here we're implicitly using the other Perl pronoun,<tt class="literal">@_</tt>, which means "them". The arguments to afunction always come in as "them". The <tt class="literal">shift</tt>operator knows to operate on <tt class="literal">@_</tt> if you omit it,just as the ride operator at Disneyland might call out "Next!" withoutspecifying which queue is supposed to shift. (There's no point inspecifying, because there's only one queue that matters.)</p><p>The <tt class="literal">||</tt> can be used to set defaults despite itsorigins as a Boolean operator, since Perl returns the first truevalue. Perl programmers often manifest a cavalier attitude toward thetruth; the line above would break if, for instance, you tried tospecify a quantity of 0. But as long as you never want to set either<tt class="literal">$quality</tt> or <tt class="literal">$quantity</tt> to a falsevalue, the idiom works great. There's no point in getting allsuperstitious and throwing in calls to <tt class="literal">defined</tt> and<tt class="literal">exists</tt> all over the place. You just have tounderstand what it's doing. As long as it won't accidentally befalse, you're fine.</p></li><li><p> Useassignment forms of operators, including control flow operators:<blockquote><pre class="programlisting">$xval = $cache{$x} ||= expensive($x);</pre></blockquote>Here we don't initialize our cache at all. We just rely on the<tt class="literal">||=</tt> operator to call<tt class="literal">expensive($x)</tt> and assign it to<tt class="literal">$cache{$x}</tt> only if <tt class="literal">$cache{$x}</tt> isfalse. The result of that is whatever the new value of<tt class="literal">$cache{$x}</tt> is. Again, we take the cavalierapproach towards truth, in that if we cache a false value,<tt class="literal">expensive($x)</tt> will get called again. Maybe theprogrammer knows that's okay, because <tt class="literal">expensive($x)</tt>isn't expensive when it returns false. Or maybe the programmer knowsthat <tt class="literal">expensive($x)</tt> never returns a false value atall. Or maybe the programmer is just being sloppy. Sloppiness can beconstrued as a form of creativity.</p></li><li><p> Use loop controls as operators, not just asstatements. And...</p></li><li><p> Use commaslike small semicolons:<blockquote><pre class="programlisting">while (<>) { $comments++, next if /^#/; $blank++, next if /^\s*$/; last if /^__END__/; $code++;}print "comment = $comments\nblank = $blank\ncode = $code\n";</pre></blockquote>This shows an understanding that statement modifiersmodify statements, while <tt class="literal">next</tt> is a mere operator. It also showsthe comma being idiomatically used to separate expressions much likeyou'd ordinarily use a semicolon. (The difference being that thecomma keeps the two expressions as part of the same statement, under thecontrol of the single statement modifier.)</p></li><li><p>Use flow control to your advantage:<blockquote><pre class="programlisting">while (<>) { /^#/ and $comments++, next; /^\s*$/ and $blank++, next; /^__END__/ and last; $code++;}print "comment = $comments\nblank = $blank\ncode = $code\n";</pre></blockquote>Here's the exact same loop again, only this time with the patterns out in front. Theperspicacious Perl programmer understands that it compiles down to exactly thesame internal codes as the previous example. The <tt class="literal">if</tt> modifier isjust a backward <tt class="literal">and</tt> (or <tt class="literal">&&</tt>) conjunction, and the <tt class="literal">unless</tt>modifier is just a backward <tt class="literal">or</tt> (or <tt class="literal">||</tt>) conjunction.</p></li><li><p>Use the implicit loops provided by the <span class="option">-n</span> and <span class="option">-p</span> switches.</p></li><li><p>Don't put semicolon at the end of a one-line block:<blockquote><pre class="programlisting">#!/usr/bin/perl -n$comments++, next LINE if /#/;$blank++, next LINE if /^\s*$/;last LINE if /^__END__/;$code++;END { print "comment = $comments\nblank = $blank\ncode = $code\n" }</pre></blockquote>This is essentially the same program as before. We put an explicit<tt class="literal">LINE</tt> label on the loop control operators because we felt like it, butwe didn't really need to, since the implicit <tt class="literal">LINE</tt> loop supplied by <tt class="userinput"><b>-n</b></tt> is the innermostenclosing loop. We used an <tt class="literal">END</tt> to get the final print statementoutside the implicit main loop, just as in <em class="emphasis">awk</em>.</p></li><li><p>Use here docs when the printing gets ferocious.</p></li><li><p>Use a meaningful delimiter on the here doc:<blockquote><pre class="programlisting">END { print <<"COUNTS" }comment = $commentsblank = $blankcode = $codeCOUNTS</pre></blockquote>Rather than using multiple prints, the fluent Perl programmer uses amultiline string with interpolation. And despite our calling it aCommon Goof earlier, we've brazenly left off the trailingsemicolon because it's not necessary at the end of the <tt class="literal">END</tt> block. (If weever turn it into a multiline block, we'll put the semicolon back in.)</p></li><li><p>Do substitutions and translations en passant on a scalar:<blockquote><pre class="programlisting">($new = $old) =~ s/bad/good/g;</pre></blockquote>Since lvalues are lvaluable, so to speak, you'll often see peoplechanging a value "in passing" while it's being assigned. This couldactually save a string copy internally (if we ever get around toimplementing the optimization):<blockquote><pre class="programlisting">chomp($answer = <STDIN>);</pre></blockquote>Any function that modifies an argument in place can do the en passanttrick. But wait, there's more!</p></li><li><p>Don't limit yourself to changing scalars en passant:<blockquote><pre class="programlisting">for (@new = @old) { s/bad/good/g }</pre></blockquote>Here we copy <tt class="literal">@old</tt> into <tt class="literal">@new</tt>, changing everything in passing(not all at once, of course--the block is executed repeatedly, one "it" at a time).</p></li><li><p>Pass named parameters using the fancy <tt class="literal">=></tt> comma operator.</p></li><li><p>Rely on assignment to a hash to do even/odd argument processing:
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -