📄 ch17_01.htm
字号:
<html><head><title>Some Advanced Perl Techniques (Learning Perl, 3rd Edition)</title><link rel="stylesheet" type="text/css" href="../style/style1.css" />
<meta name="DC.Creator" content="Randal L. Schwartz and Tom Phoenix" /><meta name="DC.Format" content="text/xml" scheme="MIME" /><meta name="DC.Language" content="en-US" /><meta name="DC.Publisher" content="O'Reilly & Associates, Inc." /><meta name="DC.Source" scheme="ISBN" content="0596001320L" /><meta name="DC.Subject.Keyword" content="stuff" /><meta name="DC.Title" content="Learning Perl, 3rd Edition" /><meta name="DC.Type" content="Text.Monograph" />
</head><body bgcolor="#ffffff">
<img alt="Book Home" border="0" src="gifs/smbanner.gif" usemap="#banner-map" /><map name="banner-map"><area shape="rect" coords="1,-2,616,66" href="index.htm" alt="Learning Perl, 3rd Edition" /><area shape="rect" coords="629,-11,726,25" href="jobjects/fsearch.htm" alt="Search this book" /></map>
<div class="navbar"><table width="684" border="0"><tr><td align="left" valign="top" width="228"><a href="ch16_05.htm"><img alt="Previous" border="0" src="../gifs/txtpreva.gif" /></a></td><td align="center" valign="top" width="228"><a href="index.htm"></a></td><td align="right" valign="top" width="228"><a href="ch17_02.htm"><img alt="Next" border="0" src="../gifs/txtnexta.gif" /></a></td></tr></table></div>
<h1 class="chapter">Chapter 17. Some Advanced Perl Techniques</h1>
<div class="htmltoc"><h4 class="tochead">Contents:</h4>
<p> <a href="#lperl3-CHP-17-SECT-1">Trapping Errors with eval</a><br />
<a href="ch17_02.htm">Picking Items from a List with grep</a><br />
<a href="ch17_03.htm">Transforming Items from a List with map</a><br />
<a href="ch17_04.htm">Unquoted Hash Keys</a><br />
<a href="ch17_05.htm">More Powerful Regular Expressions</a><br />
<a href="ch17_06.htm">Slices</a><br />
<a href="ch17_07.htm">Exercise</a><br /></p></div>
<p><a name="INDEX-1090" /></a>What we've put in the
rest of this book is the core of Perl, the part that every Perl user
should understand. But there are a few other techniques that, while
not obligatory, are still valuable tools to have in your toolbox.
We've gathered the most important of those for this chapter.
</p>
<p>Don't be misled by the title of the chapter, though; the
techniques here aren't especially more difficult to understand
than what we have elsewhere. They are "advanced" merely
in the sense that they aren't necessary for beginners. The
first time you read this book, you may want to skip (or skim) this
chapter so you can get right to using Perl. Come back to it a month
or two later, when you're ready to get even more out of Perl.
Consider this entire chapter a huge footnote<a href="#FOOTNOTE-361">[361]</a>.
</p><blockquote class="footnote"> <a name="FOOTNOTE-361" /></a><p>[361]We
contemplated doing that in one of the drafts, but got firmly rejected
by O'Reilly's editors.</p> </blockquote>
<div class="sect1"><a name="lperl3-CHP-17-SECT-1" /></a>
<h2 class="sect1">17.1. Trapping Errors with eval</h2>
<p><a name="INDEX-1091" /></a> <a name="INDEX-1092" /></a>Sometimes, your ordinary, everyday code
can cause a fatal error in your program. Each of these typical
statements could crash a program:
</p>
<blockquote><pre class="code">$barney = $fred / $dino; # divide-by-zero error?
print "match\n" if /^($wilma)/; # illegal regular expression error?
open CAVEMAN, $fred # user-generated error from die?
or die "Can't open file '$fred' for input: $!";</pre></blockquote>
<p>You could go to some trouble to catch some of these, but it's
hard to get them all. (How could you check the string
<tt class="literal">$wilma</tt> from that example to ensure that it makes a
valid regular expression?) Fortunately, Perl provides a simple way to
catch fatal errors: wrap the code in an <tt class="literal">eval</tt>
block:
</p>
<blockquote><pre class="code">eval { $barney = $fred / $dino } ;</pre></blockquote>
<p>Now, even if <tt class="literal">$dino</tt> is zero, that line won't
crash the program. The <tt class="literal">eval</tt> is actually an
expression (not a control structure, like <tt class="literal">while</tt> or
<tt class="literal">foreach</tt>) so that semicolon is required at the end
of the block.
</p>
<p>When a normally fatal error happens during the execution of an
<tt class="literal">eval</tt> block, the block is done running, but the
program doesn't crash. So that means that right after an
<tt class="literal">eval</tt> finishes, you'll be wanting to know
whether it exited normally or whether it caught a fatal error for
you. The answer is in the special <tt class="literal">$@</tt> variable. If
the <tt class="literal">eval</tt> caught a fatal error,
<tt class="literal">$@</tt> will hold what would have been the
program's dying words, perhaps something like: <tt class="literal">Illegal
division by zero at my_program line 12</tt>. If there was no
error, <tt class="literal">$@</tt> will be empty. Of course, that means
that <tt class="literal">$@</tt> is a useful Boolean (true/false) value,
true if there was an error, so you'll sometimes see code like
this after an <tt class="literal">eval</tt> block:
</p>
<blockquote><pre class="code">print "An error occurred: $@" if $@;</pre></blockquote>
<p>The <tt class="literal">eval</tt> block is a true block, so it makes a
new scope for lexical (<tt class="literal">my</tt>) variables. This piece
of a program shows an <tt class="literal">eval</tt> block hard at work:
</p>
<blockquote><pre class="code">foreach my $person (qw/ fred wilma betty barney dino pebbles /) {
eval {
open FILE, "<$person"
or die "Can't open file '$person': $!";
my($total, $count);
while (<FILE>) {
$total += $_;
$count++;
}
my $average = $total/$count;
print "Average for file $person was $average\n";
&do_something($person, $average);
};
if ($@) {
print "An error occurred ($@), continuing\n";
}
}</pre></blockquote>
<p>How many possible fatal errors are being trapped here? If there is an
error in opening the file, that error is trapped. Calculating the
average may divide by zero, so that error is trapped. Even the call
to the mysteriously named <tt class="literal">&do_something</tt>
subroutine will be protected against fatal errors, because an
<tt class="literal">eval</tt> block traps any otherwise-fatal errors that
occur during the time that it's active. (This feature is handy
if you have to call a subroutine written by someone else, and you
don't know whether they've coded defensively enough to
avoid crashing your program.)
</p>
<p>If an error occurs during the processing of one of the files,
we'll get an error message, but the program will go on to the
next file without further complaint.
</p>
<p>You can nest <tt class="literal">eval</tt> blocks inside other
<tt class="literal">eval</tt> blocks. The inner one traps errors while it
runs, keeping them from reaching the outer blocks. (Of course, after
the inner <tt class="literal">eval</tt> finishes, if it caught an error,
you may wish to re-post the error by using <tt class="literal">die</tt>,
thereby letting the outer <tt class="literal">eval</tt> catch it.) An
<tt class="literal">eval</tt> block traps any errors that occur during
its execution, including errors that happen during subroutine calls
(as we saw in the example earlier).
</p>
<p>We mentioned earlier that the <tt class="literal">eval</tt> is an
expression, which is why the trailing semicolon is needed after the
closing curly brace. But since it's an expression, it has a
return value. If there's no error, it's like a
subroutine: the return value is the last expression evaluated, or
it's returned early with an optional <tt class="literal">return</tt>
keyword. Here's another way to do the math without having to
worry about divide-by-zero:
</p>
<blockquote><pre class="code">my $barney = eval { $fred / $dino };</pre></blockquote>
<p>If the <tt class="literal">eval</tt> traps a fatal error, the return
value is either <tt class="literal">undef</tt> or an empty list, depending
upon the context. So in the previous example,
<tt class="literal">$barney</tt> is either the correct result from
dividing, or it's <tt class="literal">undef</tt>; we don't
really need to check <tt class="literal">$@</tt> (although it's
probably a good idea to check <tt class="literal">defined($barney)</tt>
before we use it further).
</p>
<p>There are four kinds of problems that <tt class="literal">eval</tt>
can't trap. The first group are the very serious errors that
crash Perl itself, such as running out of memory or getting an
untrapped signal. Since Perl itself isn't running,
there's no way it can trap these errors.<a href="#FOOTNOTE-362">[362]</a>
</p><blockquote class="footnote"> <a name="FOOTNOTE-362" /></a><p>[362]Some
of these errors are listed with an <tt class="literal">(X)</tt> code on the
<em class="emphasis">perldiag</em><a name="INDEX-1093" /></a> manpage, if
you're curious.</p> </blockquote>
<p>Of course, syntax errors inside the <tt class="literal">eval</tt> block
are caught at compile time -- they're never returned in
<tt class="literal">$@</tt>.
</p>
<p>The <tt class="literal">exit</tt> operator terminates the program at once,
even if it's called from a subroutine inside an
<tt class="literal">eval</tt> block. (This correctly implies that when
writing a subroutine, you should use <tt class="literal">die</tt> rather
than <tt class="literal">exit</tt> to signal when something goes wrong.)
</p>
<p>The fourth and final kind of problem that an
<tt class="literal">eval</tt> block can't trap are warnings, either
user-generated ones (from <tt class="literal">warn</tt>) or Perl's
internally generated warnings (requested with the
<tt class="literal">-w</tt> command-line option or the <tt class="literal">use
warnings</tt> pragma). There's a separate mechanism from
<tt class="literal">eval</tt> for trapping warnings; see the discussion of
the __<tt class="literal">WARN</tt>__ pseudosignal in the Perl
documentation for the details.
</p>
<p>We should also mention that there's another form of
<tt class="literal">eval</tt><a name="INDEX-1094" /></a> that
can be dangerous if it's mishandled. In fact, you'll
sometimes run across someone who will say that you shouldn't
use <tt class="literal">eval</tt> in your code for security reasons.
They're (mostly) right that <tt class="literal">eval</tt> should be
used only with great care, but they're talking about the
<em class="emphasis">other</em> form of <tt class="literal">eval</tt>, sometimes
called "<tt class="literal">eval</tt> of a string". If the
keyword <tt class="literal">eval</tt> is followed directly by a block of
code in curly braces, as we're doing here, there's no
need to worry -- that's the safe kind of
<tt class="literal">eval</tt>.<a name="INDEX-1095" /></a> <a name="INDEX-1096" /></a>
</p>
</div>
<hr width="684" align="left" />
<div class="navbar"><table width="684" border="0"><tr><td align="left" valign="top" width="228"><a href="ch16_05.htm"><img alt="Previous" border="0" src="../gifs/txtpreva.gif" /></a></td><td align="center" valign="top" width="228"><a href="index.htm"><img alt="Home" border="0" src="../gifs/txthome.gif" /></a></td><td align="right" valign="top" width="228"><a href="ch17_02.htm"><img alt="Next" border="0" src="../gifs/txtnexta.gif" /></a></td></tr><tr><td align="left" valign="top" width="228">16.5. Exercises</td><td align="center" valign="top" width="228"><a href="index/index.htm"><img alt="Book Index" border="0" src="../gifs/index.gif" /></a></td><td align="right" valign="top" width="228">17.2. Picking Items from a List with grep</td></tr></table></div>
<hr width="684" align="left" />
<img alt="Library Navigation Links" border="0" src="../gifs/navbar.gif" usemap="#library-map" />
<p><p><font size="-1"><a href="copyrght.htm">Copyright © 2002</a> O'Reilly & Associates. All rights reserved.</font></p>
<map name="library-map"><area shape="rect" coords="1,0,85,94" href="../index.htm"><area shape="rect" coords="86,1,178,103" href="../lwp/index.htm"><area shape="rect" coords="180,0,265,103" href="../lperl/index.htm"><area shape="rect" coords="267,0,353,105" href="../perlnut/index.htm"><area shape="rect" coords="354,1,446,115" href="../prog/index.htm"><area shape="rect" coords="448,0,526,132" href="../tk/index.htm"><area shape="rect" coords="528,1,615,119" href="../cookbook/index.htm"><area shape="rect" coords="617,0,690,135" href="../pxml/index.htm"></map>
</body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -