📄 ch10_12.htm
字号:
<HTML><HEAD><TITLE>Recipe 10.11. Prototyping Functions (Perl Cookbook)</TITLE><METANAME="DC.title"CONTENT="Perl Cookbook"><METANAME="DC.creator"CONTENT="Tom Christiansen & Nathan Torkington"><METANAME="DC.publisher"CONTENT="O'Reilly & Associates, Inc."><METANAME="DC.date"CONTENT="1999-07-02T01:39:58Z"><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="ch10_01.htm"TITLE="10. Subroutines"><LINKREL="prev"HREF="ch10_11.htm"TITLE="10.10. Returning Failure"><LINKREL="next"HREF="ch10_13.htm"TITLE="10.12. Handling Exceptions"></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="ch10_11.htm"TITLE="10.10. Returning Failure"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 10.10. Returning Failure"BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><B><FONTFACE="ARIEL,HELVETICA,HELV,SANSERIF"SIZE="-1"><ACLASS="chapter"REL="up"HREF="ch10_01.htm"TITLE="10. Subroutines"></A></FONT></B></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch10_13.htm"TITLE="10.12. Handling Exceptions"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 10.12. Handling Exceptions"BORDER="0"></A></TD></TR></TABLE></DIV><DIVCLASS="sect1"><H2CLASS="sect1"><ACLASS="title"NAME="ch10-24993">10.11. Prototyping Functions</A></H2><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch10-pgfId-1000005166">Problem<ACLASS="indexterm"NAME="ch10-idx-1000005165-0"></A><ACLASS="indexterm"NAME="ch10-idx-1000005165-1"></A></A></H3><PCLASS="para">You want to use function prototypes so the compiler can check your argument types.</P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch10-pgfId-818">Solution</A></H3><PCLASS="para">Perl has something of a prototype facility, but it isn't what you're thinking. Perl's function prototypes are more like a context coercion used to write functions that behave like some of Perl's built-ins, such as <CODECLASS="literal">push</CODE> and <CODECLASS="literal">pop</CODE>.</P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch10-pgfId-824">Discussion</A></H3><PCLASS="para"><ACLASS="indexterm"NAME="ch10-idx-1000004719-0"></A>Manually checking the validity of a function's arguments can't happen until run-time. If you make sure the function is declared before it is used, you can tickle the compiler into using a very limited form of prototype checking to help you here. Don't confuse Perl's function prototypes with those found in any other language. Perl prototypes serve only to emulate the behavior of built-in functions.</P><PCLASS="para">A Perl function prototype is zero or more spaces, backslashes, or type characters enclosed in parentheses after the subroutine definition or name. A backslashed type symbol means that the argument is passed by reference, and the argument in that position must start with that type character.</P><PCLASS="para">A prototype forces context on the arguments to the prototyped function call. This is done when Perl compiles your program, and in most cases this does not necessarily mean that Perl checks the number or type of the arguments to your function. If Perl sees <CODECLASS="literal">func(3,</CODE> <CODECLASS="literal">5)</CODE> for a function prototyped as <CODECLASS="literal">sub</CODE> <CODECLASS="literal">func</CODE> <CODECLASS="literal">($)</CODE>, it will stop with a compile-time error. But if it sees <CODECLASS="literal">func(@array)</CODE> with the same prototype, it will merely put <CODECLASS="literal">@array</CODE> into scalar context instead of saying "you can't pass an array - I'm expecting a scalar."</P><PCLASS="para">This is so important that it bears repeating: don't use Perl prototypes expecting the compiler to check type and number of arguments for you.</P><PCLASS="para">So what use are they? They have two main uses, although as you experiment with them you may find others. The first use is to tell Perl how many arguments your subroutine has, so you can leave off parentheses when you call the function. The second is to create a subroutine that has the same calling syntax as a built-in.</P><DIVCLASS="sect3"><H4CLASS="sect3"><ACLASS="title"NAME="ch10-pgfId-1000005376">Omitting parentheses</A></H4><PCLASS="para">Ordinarily your subroutines take a list of arguments, and you can omit parentheses on the function call if you like:</P><PRECLASS="programlisting">@results = myfunc 3, 5;</PRE><PCLASS="para">Without prototypes, this is the same as:</P><PRECLASS="programlisting">@results = myfunc(3, 5);</PRE><PCLASS="para">In the absence of parentheses, Perl will put the right hand side of the subroutine call into list context. You can use prototypes to change this behavior:</P><PRECLASS="programlisting">sub myfunc($);@results = myfunc 3, 5;</PRE><PCLASS="para">Now this is the same as:</P><PRECLASS="programlisting">@results = ( myfunc(3), 5 );</PRE><PCLASS="para">You can also provide an empty prototype to indicate the function takes no arguments, like the built-in function <CODECLASS="literal">time</CODE>. This is how Fcntl provides the LOCK_SH, LOCK_EX, and LOCK_UN constants. They are exported functions defined to have an empty prototype:</P><PRECLASS="programlisting">sub LOCK_SH () { 1 }sub LOCK_EX () { 2 }sub LOCK_UN () { 4 }</PRE></DIV><DIVCLASS="sect3"><H4CLASS="sect3"><ACLASS="title"NAME="ch10-pgfId-1000005427">Mimicking built-ins</A></H4><PCLASS="para">The other common use of prototypes is to give the convenient pass-without-flattening behavior of built-in functions like <CODECLASS="literal">push</CODE> and <CODECLASS="literal">shift</CODE>. When you call <CODECLASS="literal">push</CODE> as <CODECLASS="literal">push(@array,</CODE> <CODECLASS="literal">1,</CODE> <CODECLASS="literal">2,</CODE> <CODECLASS="literal">3)</CODE> the function gets a <EMCLASS="emphasis">reference</EM> to <CODECLASS="literal">@array</CODE> instead of the actual array. This is accomplished by backslashing the <CODECLASS="literal">@</CODE> character in the prototype:</P><PRECLASS="programlisting">sub mypush (\@@) { my $array_ref = shift; my @remainder = @_; # ...}</PRE><PCLASS="para">The <CODECLASS="literal">\@</CODE> in the prototype says "require the first argument to begin with an <CODECLASS="literal">@</CODE> character, and pass it by reference." The second <CODECLASS="literal">@</CODE> says "the rest of the arguments are a (possibly empty) list." A backslash in a prototype requires that the argument actually begin with the literal type character, which can sometimes be annoying. You can't even use the conditional <CODECLASS="literal">?:</CODE> construct to pick which array to pass:</P><PRECLASS="programlisting"> mypush( $x > 10 ? @a : @b , 3, 5 ); # WRONG</PRE><PCLASS="para">Instead, you must play games with references:</P><PRECLASS="programlisting"> mypush( @{ $x > 10 ? \@a : \@b }, 3, 5 ); # RIGHT</PRE><PCLASS="para">Here's an <CODECLASS="literal">hpush</CODE> function that works like <CODECLASS="literal">push</CODE>, but on <ACLASS="indexterm"NAME="ch10-idx-1000006377-0"></A>hashes. It appends a list of key/value pairs to an existing hash, overwriting previous contents for those keys.</P><PRECLASS="programlisting">sub hpush(\%@) { my $href = shift; while ( my ($k, $v) = splice(@_, 0, 2) ) { $href->{$k} = $v; } } hpush(%pieces, "queen" => 9, "rook" => 5);<ACLASS="indexterm"NAME="ch10-idx-1000004715-0"></A><ACLASS="indexterm"NAME="ch10-idx-1000004715-1"></A><ACLASS="indexterm"NAME="ch10-idx-1000004715-2"></A></PRE></DIV></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch10-pgfId-934">See Also</A></H3><PCLASS="para">The <CODECLASS="literal">prototype</CODE> function in <ICLASS="filename">perlfunc </I>(1); the section on <ACLASS="olink"HREF="../prog/ch02_07.htm#PERL2-CH-2-SECT-7.3">"Prototypes"</A> in <ACLASS="olink"HREF="../prog/ch02_01.htm">Chapter 2</A> of <ACLASS="citetitle"HREF="../prog/index.htm"TITLE="Programming Perl"><CITECLASS="citetitle">Programming Perl</CITE></A> and in <ICLASS="filename">perlsub </I>(1); <ACLASS="xref"HREF="ch10_06.htm"TITLE="Passing Arrays and Hashes by Reference">Recipe 10.5</A></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="ch10_11.htm"TITLE="10.10. Returning Failure"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 10.10. Returning Failure"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="ch10_13.htm"TITLE="10.12. Handling Exceptions"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 10.12. Handling Exceptions"BORDER="0"></A></TD></TR><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228">10.10. Returning Failure</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">10.12. Handling Exceptions</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 © 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 + -