⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 perlfaq7.html

📁 《Perl 5教程》及《perl常问问题集》
💻 HTML
📖 第 1 页 / 共 3 页
字号:
</PRE><P><PRE>    #这个函数虽然未被输出,但是可以被呼叫    sub func4(\%)  {}    #定原型为一个杂凑阵列的参考值</PRE><P><PRE>    END { }       #模组清洁大队在此 (global destructor)</PRE><P><PRE>    1;            #模组必须传回真值</PRE><P><P><HR><H2><A NAME="_p_y_O_class_H">我如何创造一个类别 (class)?</A></H2><A HREF="../../tppmsgs/msgs0.htm#57" tppabs="http://www.perl.org/CPAN/doc/manual/html/pod/perltoot.html#">perltoot</A> 里面有对於类别和物件的介绍, <A HREF="../../tppmsgs/msgs0.htm#58" tppabs="http://www.perl.org/CPAN/doc/manual/html/pod/perlobj.html#">perlobj</A> 和 <A HREF="../../tppmsgs/msgs0.htm#61" tppabs="http://www.perl.org/CPAN/doc/manual/html/pod/perlbot.html#">perlbot</A> 也有。<P><P><HR><H2><A NAME="_p_O_O_Q_V_F_t">我如何辨别一个变数是否被污染了(tainted)?</A></H2>参考 <A HREF="../../tppmsgs/msgs1.htm#102" tppabs="http://www.perl.org/CPAN/doc/manual/html/pod/perlsec.html#Laundering_and_Detecting_Tainted">Laundering and Detecting Tainted Data</A>。以下是个范例 (里面没有用到任何系统呼叫,因为 <CODE>kill()</CODE> 没有将任何程序交给讯号):<P><PRE>    sub is_tainted {        return ! eval { join('',@_), kill 0; 1; };    }</PRE><P>然而,此方法会触发 <CODE>-w</CODE>参数的警告讯息。目前并无任何不会触发 <CODE>-w</CODE>的方法可下侦测变数污染 --就把警告讯息当成是在提醒你,该把所有可能被污染的资料给 ``漂白''(untaint)。<P>【译注:这里所提的 ``被污染'' (tainted),指的是当使用 <FONT SIZE=-1>-T</FONT>这个参数时,或当 perl程式做 setuid或 setgid模式执行时 (在 <FONT SIZE=-1>UNIX</FONT> 下), perl会自动将有安 全顾虑的变数列为受污染, 也就是 tainted。除非先做解除污染 (untaint)处理,否则 perl不会容许受污染的变数做出可能危害系统的举动。因此 <FONT SIZE=-1>CGI</FONT>程式应尽可能地使用 <FONT SIZE=-1>-T</FONT>这个参数以策安全。】<P><P><HR><H2><A NAME="_closure_O_H">闭包 (closure)是啥?</A></H2>关於闭包的说明,请看 <A HREF="../../tppmsgs/msgs0.htm#59" tppabs="http://www.perl.org/CPAN/doc/manual/html/pod/perlref.html#">perlref</A><P><EM>闭包 (closure)</EM>是个精确但又很难解释的电脑名词。在 Perl 里面,闭包是以匿名函数的形式来实现,具有持续参照位於该函数范围之外的文字式变数值的能力。这些外部的文字变数会神奇地保留它们在闭包函数最初定义时的值 (深连结)。<P>如果一个程式语言容许函数递回另一个函数的话 (像 Perl 就是),闭包便具有意义。要注意的是,有些语言虽提供匿名函数的功能,但却无法正确处理闭包; Python这个语言便是一例。如果要想多了解闭包的话,建议你去找本功能性程式设计的教科书来看。Scheme这个语言不仅支援闭包,更鼓励多加使用。<P>以下是个典型的产生函数的函数:<P><PRE>    sub add_function_generator {      return sub { shift + shift };    }</PRE><P><PRE>    $add_sub = add_function_generator();    $sum = &amp;$add_sub(4,5);                # $sum现在是 9了</PRE><P>闭包用起来就像是个 <EM>函数样板</EM>,其中保留了一些可以在稍後再填入的空格。<CODE>add_function_generator()</CODE>所递回的匿名函数在技术上来讲并不能算是一个闭包,因为它没有用到任何位在这个函数范围之外的文字变数。<P>把上面这个例子和下面这个 <CODE>make_adder()</CODE>函数对照一下,下面这个函数所递回的匿名函数中使用了一个外部的文字变数。这种指名外部函数的作法需要由 Perl递回一个适当的闭包,因此那个文字变数在匿名函数产生之时的值便永久地被锁进闭 包里。<P><PRE>    sub make_adder {        my $addpiece = shift;        return sub { shift + $addpiece };    }</PRE><P><PRE>    $f1 = make_adder(20);    $f2 = make_adder(555);</PRE><P>这样一来 <CODE>&$f1($n)</CODE> 永远会是 20加上你传进去的值 <CODE>$n</CODE> ,而<CODE>&$f2($n)</CODE> 永远会是 555加上你传进去的值 <CODE>$n</CODE>。$addpiece的值会在闭包中保留下来。<P>闭包在比较实际的场合中也常用得到,譬如当你想把一些程式码传入一个函数时:<P><PRE>    my $line;    timeout( 30, sub { $line = &lt;STDIN&gt; } );</PRE><P>如果要执行的程式码当初是以字串的形式传入的话,即 <CODE>'$line =&lt;STDIN&gt;'</CODE>,那麽 <CODE>timeout()</CODE>这个假想的函数在回到该函数被呼叫时所在的范围後便无法再撷取<CODE>$list</CODE>这个文字变数的值了。<P><P><HR><H2><A NAME="_S_p_H">何谓变数自杀而我又该如何防止它?</A></H2>变数自杀指的是 (暂时或是永久)地失去一个变数的值。造成这个现象的原因是做范围界定的 <CODE>my()</CODE> 和 <CODE>local()和闭包或</CODE> <CODE>foreach()</CODE>回圈变数及函数参数相互影响 所致。<P>从前【在旧版 perl的时代】大家写程式的时候很容易因为这样而不小心把变数值给弄丢。但现在 perl提供了一些保护措施,因此犯这种错的机率要小多了。<P><PRE>    my $f = &quot;foo&quot;;    sub T {      while ($i++ &lt; 3) { my $f = $f; $f .= &quot;bar&quot;; print $f, &quot;\n&quot; }    }    T;    print &quot;Finally $f\n&quot;;</PRE><P>有叁个 ``bar''加进去的 <CODE>$f</CODE>变数应该是一个新的 <CODE>$f</CODE> (因为 <CODE>my $f</CODE>在每个回圈都应该创造一个新的区域变数)。然而,实际上并非如此。这个臭虫在未来的 perl 版本中将会被修正。<P><P><HR><H2><A NAME="_p_A_">我如何传递/传回一个 {函数,档案把手,阵列,杂凑阵列,方法,和正规表现式}?</A></H2>除了正规表现式这个特例外,你需要以传参考值的方式传资料给这些物件。参看<A HREF="../../tppmsgs/msgs0.htm#66" tppabs="http://www.perl.org/CPAN/doc/manual/html/pod/perlsub.html#Pass_by_Reference">Pass by Reference</A>,里面有针对此问题的讨论,以及 <A HREF="../../tppmsgs/msgs0.htm#59" tppabs="http://www.perl.org/CPAN/doc/manual/html/pod/perlref.html#">perlref</A> 里面有参考值的资讯。<P><DL><DT><STRONG><A NAME="item__M_">传递变数和函数</A></STRONG><DD>一般的变数和函数是相当简单的:只要传一个指向现存的匿名变数或函数的参考值即可:<P><PRE>    func( \$some_scalar );</PRE><P><PRE>    func( \$some_array );    func( [ 1 .. 10 ]   );</PRE><P><PRE>    func( \%some_hash   );    func( { this =&gt; 10, that =&gt; 20 }   );</PRE><P><PRE>    func( \&amp;some_func   );    func( sub { $_[0] ** $_[1] }   );</PRE><P><DT><STRONG><A NAME="item__">传递档案把手</A></STRONG><DD>要创造出可以传递给函数使用的档案把手,你可以用 <CODE>*FH</CODE>或 <CODE>\*FH</CODE> (这叫 ``typeglobs'' --请参看 <A HREF="../../tppmsgs/msgs0.htm#99" tppabs="http://www.perl.org/CPAN/doc/manual/html/pod/perldata.html#">perldata</A>),或是使用旧名 FileHandle的 IO::File模组以动态方式来产生档案把手亦可,这两个模组都附在标准 Perl 版本内。<P><PRE>    use Fcntl;    use IO::File;    my $fh = new IO::File $filename, O_WRONLY|O_APPEND;                or die &quot;Can't append to $filename: $!&quot;;    func($fh);</PRE><P><DT><STRONG><A NAME="item__W_">传递正规表示式</A></STRONG><DD>想要将正规表现式传来传去,你需要的将是使用 <FONT SIZE=-1>CPAN</FONT> 里一个实验性的正规表现式模组( Nick Ing-Simmons的 Regexp或 Ilya Zakharevich的Devel::Regexp),来传递字串,并且使用一个能捕捉例外情况的 eval叙述,或者你自己可以发明其他非常非常聪明的方式来做。以下就是一个如何以字串当作正规表现式,传入一个做比较的函数的例子:<P><PRE>    sub compare($$) {        my ($val1, $regexp) = @_;        my $retval = eval { $val =~ /$regexp/ };        die if $@;        return $retval;    }</PRE><P><PRE>    $match = compare(&quot;old McDonald&quot;, q/d.*D/);</PRE><P>确定绝对不要用以下的写法:<P><PRE>    return eval &quot;\$val =~ /$regexp/&quot;;   #错误</PRE><P>不然某人可以靠双引号括起来的字串以及 eval 双重解译的本质而偷偷插入 shell指令来作坏事。例如:<P><PRE>    $pattern_of_evil = 'danger ${ system(&quot;rm -rf * &amp;&quot;) } danger';</PRE><P><PRE>    eval &quot;\$string =~ /$pattern_of_evil/&quot;;</PRE><P>想学非常非常聪明的方法的读者可以参考 O'Reilly 出的 <EM>Mastering RegularExpressions</EM>这本书,作者是 Jeffrey Friedl。其中第 273页的<CODE>Build_MatchMany_Function()</CODE>特别的有趣。在 <A HREF="perlfaq2.html#" tppabs="http://202.96.217.5/~xiaoyi/perlfaq2.html#">perlfaq2</A>中可以找到有关本书 的资料。<P><DT><STRONG><A NAME="item__p_k">如何传递方法 (methods)</A></STRONG><DD>你可以用下面的方法传递一个物件方法给一个函式:<P><PRE>    call_a_lot(10, $some_obj, &quot;methname&quot;)    sub call_a_lot {        my ($count, $widget, $trick) = @_;        for (my $i = 0; $i &lt; $count; $i++) {            $widget-&gt;$trick();        }    }</PRE><P>不然你就用个闭包 (closure)把物件和它的方法以及其参数都包在一起:<P><PRE>    my $whatnot =  sub { $some_obj-&gt;obfuscate(@args) };    func($whatnot);    sub func {        my $code = shift;        &amp;$code();    }</PRE><P>你也可以研究 <FONT SIZE=-1>UNIVERSAL</FONT> 类别中的 <CODE>can()</CODE>方法 (附於标准 Perl 版本中)。<P></DL><P><HR><H2><A NAME="_p_R_A_H">我如何生成一个静态变数?</A></H2>就像与 Perl相关的其他事情一样,``条条大路通罗马'' (TMTOWTDI)。对其他语言来说叫做 ``静态变数'' (static variable)的东西,在 Perl里面可能是一个函数私有的变数(只有该函数自己看得到,且在不同的呼叫间保持定值),或是一个档案私有(file-private)变数(只有同一个档案中的函数才看得到)。<P>以下就是实作函数私有变数的程式:<P><PRE>    BEGIN {        my $counter = 42;        sub prev_counter { return --$counter }        sub next_counter { return $counter++ }    }</PRE><P><CODE>prev_counter()</CODE> 和 <CODE>next_counter()</CODE>将会共用一个於编译时起始的私有变数 $counter。<P>要宣告一个档案私有(file-private)变数,你仍然得使用<CODE>my(),将它放在档案开</CODE>头处最外围。假设现在是在 Pax.pm这个档案里:<P><PRE>    package Pax;    my $started = scalar(localtime(time()));</PRE><P><PRE>    sub begun { return $started }</PRE><P>当用 <CODE>use Pax</CODE>或 <CODE>require Pax</CODE>载入此模组时,这个变数就会被起始。不过它不会被资源回收,像其他出了有效范围的变数那样,因为 <CODE>begun()</CODE>函数要用到它,但是没有其他函数能撷取它。这个变数不能以 $Pax::started 的形式来撷取,因为它所存在的范围与此包裹无关。它存在的范围是这个档案。可想见地,一个档案里可以放好几个包裹,而所有的包裹都撷取同一个私有变数,但从另一个档案中,即使是属於同一个包裹(package),也不能取得它的值。<P><P><HR><H2><A NAME="_A_P_r_R_A_d_w_scop">动态与文字式(静态)范围界定 (scoping)有何不同? Local()和 my()呢?</A></H2><CODE>local($x)</CODE> 将全域变数 <CODE>$x</CODE>的原值存起来,并在此函数执行期间赋予一个新 值,<EM>此值可以从此函数所呼叫的其他函数里看见</EM>。这整个步骤是在执行期间完成的,所以才叫做动态范围选取 (dynamicscoping)。local()影响的是全域变数,或者称作包裹变数或动态变数。<P><CODE>my($x)</CODE>会创造一个只能在目前这个函数里看得见的新变数。这个步骤是在编译期完成(compile-time),所以称作文字式或是静态范围选取。my()总是作用在私有变数,也称作文字式变数或(不当地)称作静态(范围选取)变数。<P>例如:<P><PRE>    sub visible {        print &quot;var has value $var\n&quot;;    }</PRE><P>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -