ch12_04.htm

来自「By Tom Christiansen and Nathan Torkingto」· HTM 代码 · 共 506 行

HTM
506
字号
<HTML><HEAD><TITLE>Recipe 12.3. Delaying use Until Run Time (Perl Cookbook)</TITLE><METANAME="DC.title"CONTENT="Perl Cookbook"><METANAME="DC.creator"CONTENT="Tom Christiansen &amp; Nathan Torkington"><METANAME="DC.publisher"CONTENT="O'Reilly &amp; Associates, Inc."><METANAME="DC.date"CONTENT="1999-07-02T01:41:24Z"><METANAME="DC.type"CONTENT="Text.Monograph"><METANAME="DC.format"CONTENT="text/html"SCHEME="MIME"><METANAME="DC.source"CONTENT="1-56592-243-3"SCHEME="ISBN"><METANAME="DC.language"CONTENT="en-US"><METANAME="generator"CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"><LINKREV="made"HREF="mailto:online-books@oreilly.com"TITLE="Online Books Comments"><LINKREL="up"HREF="ch12_01.htm"TITLE="12. Packages, Libraries, and Modules"><LINKREL="prev"HREF="ch12_03.htm"TITLE="12.2. Trapping Errors in require or use"><LINKREL="next"HREF="ch12_05.htm"TITLE="12.4. Making Variables Private to a Module"></HEAD><BODYBGCOLOR="#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="Perl Cookbook"><area shape="rect" coords="629,-11,726,25" href="jobjects/fsearch.htm" alt="Search this book" /></map><div class="navbar"><p><TABLEWIDTH="684"BORDER="0"CELLSPACING="0"CELLPADDING="0"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch12_03.htm"TITLE="12.2. Trapping Errors in require or use"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 12.2. Trapping Errors in require or use"BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><B><FONTFACE="ARIEL,HELVETICA,HELV,SANSERIF"SIZE="-1"><ACLASS="chapter"REL="up"HREF="ch12_01.htm"TITLE="12. Packages, Libraries, and Modules"></A></FONT></B></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch12_05.htm"TITLE="12.4. Making Variables Private to a Module"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 12.4. Making Variables Private to a Module"BORDER="0"></A></TD></TR></TABLE></DIV><DIVCLASS="sect1"><H2CLASS="sect1"><ACLASS="title"NAME="ch12-19732">12.3. Delaying use Until Run Time</A></H2><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch12-pgfId-492">Problem<ACLASS="indexterm"NAME="ch12-idx-1000005185-0"></A><ACLASS="indexterm"NAME="ch12-idx-1000005185-1"></A><ACLASS="indexterm"NAME="ch12-idx-1000005185-2"></A><ACLASS="indexterm"NAME="ch12-idx-1000005185-3"></A><ACLASS="indexterm"NAME="ch12-idx-1000005185-4"></A></A></H3><PCLASS="para">You have a module that you don't need to load each time the program runs, or whose inclusion you wish to delay until after the program starts up.</P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch12-pgfId-498">Solution</A></H3><PCLASS="para">Either break up the <CODECLASS="literal">use</CODE> into its separate <CODECLASS="literal">require</CODE> and <CODECLASS="literal">import</CODE> components, or else employ the <CODECLASS="literal">use</CODE> <CODECLASS="literal">autouse</CODE> pragma.</P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch12-pgfId-504">Discussion</A></H3><PCLASS="para">Programs that check their arguments and abort with a usage message on error have no reason to load modules they'll never use. This delays the inevitable and annoys users. But those <CODECLASS="literal">use</CODE> statements happen during compilation, not execution, as explained in the Introduction.</P><PCLASS="para">Here, an effective strategy is to place argument checking in a <CODECLASS="literal">BEGIN</CODE> block before loading the modules. The following is the start of a program that checks to make sure it was called with exactly two arguments, which must be whole numbers, before going on to load the modules it will need:</P><PRECLASS="programlisting">BEGIN {    unless (@ARGV == 2 &amp;&amp; (2 == grep {/^\d+$/} @ARGV)) {        die &quot;usage: $0 num1 num2\n&quot;;    }}use Some::Module;use More::Modules;</PRE><PCLASS="para">A related situation arises in programs that don't always use the same set of modules every time they're run. For example, the <EMCLASS="emphasis">factors</EM> program from <ACLASS="xref"HREF="ch02_01.htm"TITLE="Numbers">Chapter 2, <CITECLASS="chapter">Numbers</CITE></A>, needs the infinite precision arithmetic library only when the <BCLASS="emphasis.bold">-b</B> command-line flag is supplied. A <CODECLASS="literal">use</CODE> statement would be pointless within a conditional because it's evaluated at compile time, long before the <CODECLASS="literal">if</CODE> can be checked. So we'll use a <CODECLASS="literal">require</CODE> instead:</P><PRECLASS="programlisting">if ($opt_b) {    require Math::BigInt;}</PRE><PCLASS="para">Because Math::BigInt is an object-oriented module instead of a traditional one, no import was needed. If you have an import list, specify it with a <CODECLASS="literal">qw()</CODE> construct as you would with <CODECLASS="literal">use</CODE>. For example, rather than this:</P><PRECLASS="programlisting">use Fcntl qw(O_EXCL O_CREAT O_RDWR);</PRE><PCLASS="para">you might say this instead:</P><PRECLASS="programlisting">require Fcntl;Fcntl-&gt;import(qw(O_EXCL O_CREAT O_RDWR));</PRE><PCLASS="para">Delaying the import until run time means that the rest of your program will not be subject to any imported semantic changes that the compiler would have seen if you'd used a <CODECLASS="literal">use</CODE>. In particular, subroutine prototypes and the overriding of built-in functions will not be seen in time.</P><PCLASS="para">You might want to encapsulate this delayed loading in a subroutine. The following deceptively simple approach does not work:</P><PRECLASS="programlisting">sub load_module {    require $_[0];  #WRONG    import  $_[0];  #WRONG}</PRE><PCLASS="para">It fails for subtle reasons. Imagine calling <CODECLASS="literal">require</CODE> with an argument of <CODECLASS="literal">&quot;Math::BigFloat&quot;</CODE>. If that's a bareword, the double colon is converted into your operating system's path separator and a trailing <CODECLASS="literal">.pm</CODE> is added. But as a simple variable, it's a literal filename. Worse, Perl doesn't have a built-in <CODECLASS="literal">import</CODE> function. Instead, there's a class method named <CODECLASS="literal">import</CODE> that we're using the dubious indirect object syntax on. As with indirect filehandles, you can't use indirect objects on anything but a plain scalar variable, or a bareword or a block returning the object, not an expression or one element from an array or hash.</P><PCLASS="para">A better implementation might look more like:</P><PRECLASS="programlisting">load_module('Fcntl', qw(O_EXCL O_CREAT O_RDWR));sub load_module {    eval &quot;require $_[0]&quot;;    die if $@;    $_[0]-&gt;import(@_[1 .. $#_]);}</PRE><PCLASS="para">But this still isn't perfectly correct in the general case. It really shouldn't import those symbols into its own package. It should put them into its caller's package. We could account for this, but the whole procedure is getting increasingly messy.</P><PCLASS="para">A convenient alternative is the <CODECLASS="literal">use</CODE> <CODECLASS="literal">autouse</CODE> pragma. New as of Perl 5.004, this directive can save time on infrequently loaded functions by delaying their loading until they're actually used:</P><PRECLASS="programlisting">use autouse Fcntl =&gt; qw( O_EXCL() O_CREAT() O_RDWR() );</PRE><PCLASS="para">We put parentheses after <CODECLASS="literal">O_EXCL </CODE>, <CODECLASS="literal">O_CREAT </CODE>, and <CODECLASS="literal">O_RDWR</CODE> when we <CODECLASS="literal">autouse</CODE>d them but not when we <CODECLASS="literal">use</CODE>d them or <CODECLASS="literal">import</CODE>ed them. The <CODECLASS="literal">autouse</CODE> pragma doesn't just take function names, it can also take a prototype for the function. The Fcntl constants are prototyped to take no arguments, so we can use them as barewords in our program without <CODECLASS="literal">use</CODE> <CODECLASS="literal">strict</CODE> kvetching.</P><PCLASS="para">Remember, too, that <CODECLASS="literal">use</CODE> <CODECLASS="literal">strict</CODE>'s checks take place at compile time. If we <CODECLASS="literal">use</CODE> <CODECLASS="literal">Fcntl</CODE>, the prototypes in the Fcntl module will be compiled and we can use the constants without parentheses. If we <CODECLASS="literal">require</CODE> or wrap the <CODECLASS="literal">use</CODE> in an <CODECLASS="literal">eval</CODE>, as we did earlier, we prevent the compiler from reading the prototypes, so we can't use the Fcntl constants without parentheses.</P><PCLASS="para">Read the <CODECLASS="literal">autouse</CODE> pragma's online documentation to learn its various caveats and provisos.<ACLASS="indexterm"NAME="ch12-idx-1000005200-0"></A><ACLASS="indexterm"NAME="ch12-idx-1000005200-1"></A><ACLASS="indexterm"NAME="ch12-idx-1000005200-2"></A><ACLASS="indexterm"NAME="ch12-idx-1000005200-3"></A></P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch12-pgfId-586">See Also</A></H3><PCLASS="para"><ACLASS="xref"HREF="ch12_03.htm"TITLE="Trapping Errors in require or use">Recipe 12.2</A>; the discussion on the <CODECLASS="literal">import</CODE> method in the documentation for the standard Exporter module, also found in <ACLASS="olink"HREF="../prog/ch07_01.htm">Chapter 7</A> of <ACLASS="citetitle"HREF="../prog/index.htm"TITLE="Programming Perl"><CITECLASS="citetitle">Programming Perl</CITE></A>; the documentation for the standard <CODECLASS="literal">use</CODE> <CODECLASS="literal">autouse</CODE> pragma</P></DIV></DIV><DIVCLASS="htmlnav"><P></P><HRALIGN="LEFT"WIDTH="684"TITLE="footer"><TABLEWIDTH="684"BORDER="0"CELLSPACING="0"CELLPADDING="0"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch12_03.htm"TITLE="12.2. Trapping Errors in require or use"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 12.2. Trapping Errors in require or use"BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><ACLASS="book"HREF="index.htm"TITLE="Perl Cookbook"><IMGSRC="../gifs/txthome.gif"ALT="Perl Cookbook"BORDER="0"></A></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch12_05.htm"TITLE="12.4. Making Variables Private to a Module"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 12.4. Making Variables Private to a Module"BORDER="0"></A></TD></TR><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228">12.2. Trapping Errors in require or use</TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><ACLASS="index"HREF="index/index.htm"TITLE="Book Index"><IMGSRC="../gifs/index.gif"ALT="Book Index"BORDER="0"></A></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228">12.4. Making Variables Private to a Module</TD></TR></TABLE><HRALIGN="LEFT"WIDTH="684"TITLE="footer"><FONTSIZE="-1"></DIV<!-- LIBRARY NAV BAR --> <img src="../gifs/smnavbar.gif" usemap="#library-map" border="0" alt="Library Navigation Links"><p> <a href="copyrght.htm">Copyright &copy; 2002</a> O'Reilly &amp; 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 + =
减小字号Ctrl + -
显示快捷键?