📄 ch24_01.htm
字号:
<html><head><title>Common Practices (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="Common Practices"><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="ch23_03.htm"><img src="../gifs/txtpreva.gif" alt="Previous" border="0"></a></td><td align="center" valign="top" width="171"><a href="part4.htm">Part 4: Perl as Culture</a></td><td align="right" valign="top" width="172"><a href="ch24_02.htm"><img src="../gifs/txtnexta.gif" alt="Next" border="0"></a></td></tr></table></div><hr width="515" align="left"><!-- SECTION BODY --><h1 class="chapter">Chapter 24. Common Practices</h1><div class="htmltoc"><h4 class="tochead">Contents:</h4><p><a href="ch24_01.htm">Common Goofs for Novices</a><br><a href="ch24_02.htm">Efficiency</a><br><a href="ch24_03.htm">Programming with Style</a><br><a href="ch24_04.htm">Fluent Perl</a><br><a href="ch24_05.htm">Program Generation</a><br></p></div><a name="INDEX-4096"></a><a name="INDEX-4097"></a><p>Ask almost any Perl programmer, and they'll be glad to give you reamsof advice on how to program. We're no different (in case you hadn'tnoticed). In this chapter, rather than trying to tell you aboutspecific features of Perl, we'll go at it from the other direction anduse a more scattergun approach to describe idiomatic Perl. Our hope isthat, by putting together various bits of things that seemingly aren'trelated, you can soak up some of the feeling of what it's like toactually "think Perl". After all, when you're programming, you don'twrite a bunch of expressions, then a bunch of subroutines, then a bunchof objects. You have to go at everything all at once, more or less.So this chapter is a bit like that.</p><p>There is, however, a rudimentary organization to the chapter, in thatwe'll start with the negative advice and work our way towards the positiveadvice. We don't know if that will make you feel any better, but it makesus feel better.</p><h2 class="sect1">24.1. Common Goofs for Novices</h2><p><a name="INDEX-4098"></a><a name="INDEX-4099"></a><a name="INDEX-4100"></a><a name="INDEX-4101"></a><a name="INDEX-4102"></a>The biggest goof of all is forgetting to <tt class="literal">usewarnings</tt>, which identifies many errors. The second biggestgoof is forgetting to <tt class="literal">use strict</tt> when it'sappropriate. These two pragmas can save you hours of head-bangingwhen your program starts getting bigger. (And it will.) Yet anotherfaux pas is to forget to consult the online FAQ. Suppose you want tofind out if Perl has a <tt class="literal">round</tt> function. You mighttry searching the FAQ first:<blockquote><pre class="programlisting">% <tt class="userinput"><b>perlfaq round</b></tt></pre></blockquote>Apart from those "metagoofs", there are several kinds of programmingtraps. Some traps almost everyone falls into, and other traps you'llfall into only if you come from a particular culture that does thingsdifferently. We've separated these out in the following sections.</p><h3 class="sect2">24.1.1. Universal Blunders</h3><ul><li><p><a name="INDEX-4103"></a><a name="INDEX-4104"></a>Putting a comma after the filehandle in a <tt class="literal">print</tt>statement. Although it looks extremely regular and pretty to say:<blockquote><pre class="programlisting">print STDOUT, "goodbye", $adj, "world!\n"; # WRONG</pre></blockquote>this is nonetheless incorrect, because of that first comma. What youwant instead is the indirect object syntax:<blockquote><pre class="programlisting">print STDOUT "goodbye", $adj, "world!\n"; # ok</pre></blockquote>The syntax works this way so that you can say:<blockquote><pre class="programlisting">print $filehandle "goodbye", $adj, "world!\n";</pre></blockquote>where <tt class="literal">$filehandle</tt> is a scalar holding the name of afilehandle at run time. This is distinct from:<blockquote><pre class="programlisting">print $notafilehandle, "goodbye", $adj, "world!\n";</pre></blockquote>where <tt class="literal">$notafilehandle</tt> is simply a string that ispart of the list of things to be printed. See "indirect object" inthe Glossary.</p></li><li><p><a name="INDEX-4105"></a><a name="INDEX-4106"></a><a name="INDEX-4107"></a><a name="INDEX-4108"></a><a name="INDEX-4109"></a><a name="INDEX-4110"></a>Using <tt class="literal">==</tt> instead of <tt class="literal">eq</tt> and<tt class="literal">!=</tt> instead of <tt class="literal">ne</tt>. The<tt class="literal">==</tt> and <tt class="literal">!=</tt> operators are<em class="emphasis">numeric</em> tests. The other two are<em class="emphasis">string</em> tests. The strings<tt class="literal">"123"</tt> and <tt class="literal">"123.00"</tt> are equal asnumbers, but not equal as strings. Also, any nonnumeric string isnumerically equal to zero. Unless you are dealing with numbers, youalmost always want the string comparison operators instead.</p></li><li><p><a name="INDEX-4111"></a>Forgetting the trailing semicolon. Every statement in Perl isterminated by a semicolon or the end of a block. Newlines aren'tstatement terminators as they are in <em class="emphasis">awk</em>, Python,or FORTRAN. Remember that Perl is like C.</p><p><a name="INDEX-4112"></a>A statement containing a here document is particularly prone to losingits semicolon. It ought to look like this:<blockquote><pre class="programlisting">print <<'FINIS';A foolish consistency is the hobgoblin of little minds,adored by little statesmen and philosophers and divines. --Ralph Waldo EmersonFINIS</pre></blockquote></p></li><li><p><a name="INDEX-4113"></a>Forgetting that a <em class="replaceable">BLOCK</em> requires braces. Naked statements are not<em class="replaceable">BLOCK</em>s. If you are creating a control structure such as a <tt class="literal">while</tt>or an <tt class="literal">if</tt> that requires one or more <em class="replaceable">BLOCK</em>s, you <em class="emphasis">must</em> use bracesaround each <em class="replaceable">BLOCK</em>. Remember that Perl is <em class="emphasis">not</em> like C.</p></li><li><p><a name="INDEX-4114"></a><a name="INDEX-4115"></a><a name="INDEX-4116"></a><a name="INDEX-4117"></a><a name="INDEX-4118"></a>Not saving <tt class="literal">$1</tt>, <tt class="literal">$2</tt>, and so on, across regularexpressions. Remember that every new <tt class="literal">m/atch/</tt> or <tt class="literal">s/ubsti/tution/</tt>will set (or clear, or mangle) your <tt class="literal">$1</tt>, <tt class="literal">$2</tt>...variables, as wellas <tt class="literal">$`</tt>, <tt class="literal">$&</tt>, and <tt class="literal">$'</tt>. One way to save them right away is toevaluate the match within a list context, as in:<blockquote><pre class="programlisting">my ($one, $two) = /(\w+) (\w+)/;</pre></blockquote></p></li><li><p><a name="INDEX-4119"></a><a name="INDEX-4120"></a>Not realizing that a <tt class="literal">local</tt> also changes thevariable's value as seen by other subroutines called within the scopeof the local. It's easy to forget that <tt class="literal">local</tt> is arun-time statement that does dynamic scoping, because there's noequivalent in languages like C. See the section "ScopedDeclarations" in<a href="ch04_01.htm">Chapter 4, "Statements and Declarations"</a>. Usually you want a<tt class="literal">my</tt> anyway.</p></li><li><p>Losing track of brace pairings. A good text editor will help you findthe pairs. Get one. (Or two.)</p></li><li><p><a name="INDEX-4121"></a><a name="INDEX-4122"></a> Using loop controlstatements in <tt class="literal">do {} while</tt>. Although the braces inthis control structure look suspiciously like part of a loop<em class="replaceable">BLOCK</em>, they aren't.</p></li><li><p> Saying <tt class="literal">@foo[1]</tt> when you mean<tt class="literal">$foo[1]</tt>. The <tt class="literal">@foo[1]</tt> referenceis an array <em class="emphasis">slice</em>, meaning an array consisting ofthe single element <tt class="literal">$foo[1]</tt>. Sometimes this doesn'tmake any difference, as in:<blockquote><pre class="programlisting">print "the answer is @foo[1]\n";</pre></blockquote>but it makes a big difference for things like:<blockquote><pre class="programlisting">@foo[1] = <STDIN>;</pre></blockquote>which will slurp up all the rest of <tt class="literal">STDIN</tt>, assignthe <em class="emphasis">first</em> line to <tt class="literal">$foo[1]</tt>, anddiscard everything else. This is probably not what you intended. Getinto the habit of thinking that <tt class="literal">$</tt> means a singlevalue, while <tt class="literal">@</tt> means a list of values, and you'lldo okay.</p></li><li><p><a name="INDEX-4123"></a>Forgetting the parentheses of a list operator like <tt class="literal">my</tt>:<blockquote><pre class="programlisting">my $x, $y = (4, 8); # WRONG my ($x, $y) = (4, 8); # ok</pre></blockquote></p></li><li><p><a name="INDEX-4124"></a>Forgetting to select the right filehandle before setting<tt class="literal">$^</tt>, <tt class="literal">$~</tt>, or<tt class="literal">$|</tt>. These variables depend on the currentlyselected filehandle, as determined by<tt class="literal">select(</tt><em class="replaceable">FILEHANDLE</em><tt class="literal">)</tt>. Theinitial filehandle so selected is <tt class="literal">STDOUT</tt>. Youshould really be using the filehandle methods from the<tt class="literal">FileHandle</tt> module instead. See <a href="ch28_01.htm">Chapter 28, "Special Names"</a>.</p></li></ul><h3 class="sect2">24.1.2. Frequently Ignored Advice</h3><p>Practicing Perl Programmers should take note of the following:</p><ul><li><p><a name="INDEX-4125"></a><a name="INDEX-4126"></a>Remember that many operations behave differently in a list context thanthey do in a scalar one. For instance:<blockquote><pre class="programlisting">($x) = (4, 5, 6); # List context; $x is set to 4 $x = (4, 5, 6); # Scalar context; $x is set to 6 @a = (4, 5, 6); $x = @a; # Scalar context; $x is set to 3 (the array list)</pre></blockquote></p></li><li><p><a name="INDEX-4127"></a><a name="INDEX-4128"></a>Avoid barewords if you can, especially all lowercase ones. You can'ttell just by looking at it whether a word is a function or a barewordstring. By using quotes on strings and parentheses around functioncall arguments, you won't ever get them confused. In fact, the pragma<tt class="literal">use strict</tt> at the beginning of your program makesbarewords a compile-time error--probably a good thing.</p></li><li><p> You can't tell just by lookingwhich built-in functions are unary operators (like<tt class="literal">chop</tt> and <tt class="literal">chdir</tt>), which are listoperators (like <tt class="literal">print</tt> and<tt class="literal">unlink</tt>), and which are argumentless (like<tt class="literal">time</tt>). You'll want to learn them by reading <a href="ch29_01.htm">Chapter 29, "Functions"</a>. As always, use parentheses if youaren't sure--or even if you aren't sure you're sure. Note also thatuser-defined subroutines are by default list operators, but they canbe declared as unary operators with a prototype of<tt class="literal">($)</tt> or argumentless with a prototype of<tt class="literal">()</tt>.</p></li><li><p> Peoplehave a hard time remembering that some functions default to<tt class="literal">$_</tt>, or <tt class="literal">@ARGV</tt>, orwhatever, while others do not. Take the time to learn which arewhich, or avoid default arguments.</p></li><li><p><a name="INDEX-4129"></a><a name="INDEX-4130"></a><tt class="literal"><FH></tt> is not the name of a filehandle, but anangle operator that does a line-input operation on the handle. Thisconfusion usually manifests itself when people try to<tt class="literal">print</tt> to the angle operator:<blockquote><pre class="programlisting">print <FH> "hi"; # WRONG, omit angles</pre></blockquote></p></li><li><p>Remember also that data read by the angle operator is assigned to<tt class="literal">$_</tt> only when the file read is the sole condition ina <tt class="literal">while</tt> loop:<blockquote><pre class="programlisting">while (<FH>) { } # Data assigned to $_.<FH>; # Data read and discarded!</pre></blockquote></p></li><li><p>Don't use <tt class="literal">=</tt> when you need <tt class="literal">=~</tt>;the two constructs are quite different:<blockquote><pre class="programlisting">$x = /foo/; # Searches $_ for "foo", puts result in $x$x =~ /foo/; # Searches $x for "foo", discards result</pre></blockquote></p></li><li><p><a name="INDEX-4131"></a><a name="INDEX-4132"></a><a name="INDEX-4133"></a><a name="INDEX-4134"></a>Use <tt class="literal">my</tt> for local variables whenever you can getaway with it. Using <tt class="literal">local</tt> merely gives a temporaryvalue to a global variable, which leaves you open to unforeseen sideeffects of dynamic scoping.</p></li><li><p>Don't use <tt class="literal">local</tt> on a module's exported variables.If you localize an exported variable, its exported value will notchange. The local name becomes an alias to a new value but theexternal name is still an alias for the original.</p></li></ul><h3 class="sect2">24.1.3. C Traps</h3><p><a name="INDEX-4135"></a><a name="INDEX-4136"></a>Cerebral C programmers should take note of the following:</p><ul><li><p>Curlies are required for <tt class="literal">if</tt> and <tt class="literal">while</tt> blocks.</p></li><li><p><a name="INDEX-4137"></a>You must use <tt class="literal">elsif</tt> rather than "else if" or"elif". Syntax like this:<blockquote><pre class="programlisting">if (expression) { block;}else if (another_expression) { # WRONG another_block;}</pre></blockquote>is illegal. The <tt class="literal">else</tt> part is always a block, and anaked <tt class="literal">if</tt> is not a block. You mustn't expect Perl tobe exactly the same as C. What you want instead is:<blockquote><pre class="programlisting">if (expression) { block;}elsif (another_expression) { another_block;}</pre></blockquote>Note also that "elif" is "file" spelled backward. OnlyAlgol-ers would want a keyword that was the same as another wordspelled backward.</p></li><li><p><a name="INDEX-4138"></a><a name="INDEX-4139"></a>The <tt class="literal">break</tt> and <tt class="literal">continue</tt> keywordsfrom C become in Perl <tt class="literal">last</tt> and<tt class="literal">next</tt>, respectively. Unlike in C, these do<em class="emphasis">not</em> work within a <tt class="literal">do {} while</tt>construct.<a name="INDEX-4140"></a><a name="INDEX-4141"></a></p></li><li><p><a name="INDEX-4142"></a>There's no switch statement. (But it's easy to build one on the fly;see "Bare Blocks" and "Case Structures" in <a href="ch04_01.htm">Chapter 4, "Statements and Declarations"</a>.)</p></li><li><p><a name="INDEX-4143"></a>Variables begin with <tt class="literal">$</tt>, <tt class="literal">@</tt>, or <tt class="literal">%</tt> in Perl.</p></li><li><p><a name="INDEX-4144"></a>Comments begin with <tt class="literal">#</tt>, not <tt class="literal">/*</tt>.</p></li><li><p><a name="INDEX-4145"></a>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -