📄 perlfaq7.html
字号:
<PRE> sub dynamic { local $var = 'local'; #授予 $var这个全域变数 visible(); #一个暂时的新值 }</PRE><P><PRE> sub lexical { my $var = 'private'; #新的私有变数,$var visible(); # (无法从此函数外看到) }</PRE><P><PRE> $var = 'global';</PRE><P><PRE> visible(); #会印出 global dynamic(); #会印出 local lexical(); #会印出 global</PRE><P>你可以发现在整个过程中 ``private''这个值都印不出来。那是因为<CODE>$var</CODE>的值只存在於lexical()函数的区块里面,对它所呼叫的函数来说是看不到的。<P>总结来说,local()不会产生你想像中的私有、区域变数。它只是将一个暂时的值授予一个全域变数。如果你要的是私有的变数,那麽 <CODE>my()</CODE>才是你要找的。<P>参看 <A HREF="../../tppmsgs/msgs0.htm#66" tppabs="http://www.perl.org/CPAN/doc/manual/html/pod/perlsub.html#">perlsub</A>,里面有更详尽的解说。<P><P><HR><H2><A NAME="_P_d_r_">当同一个范围中有一个文字式变数时,我该如何去撷取同名的动态变数?</A></H2>你可以透过符号式参考值 (symbolic references),把 <CODE>use strict "refs"</CODE>设定取掉。然後使用 <CODE>${'var'}</CODE>,而非 $var。<P><PRE> local $var = "global"; my $var = "lexical";</PRE><P><PRE> print "lexical is $var\n";</PRE><P><PRE> no strict 'refs'; print "global is ${'var'}\n";</PRE><P>如果你知道你所在的是哪一个包裹(package)的话,你可以直接指名,就像写$Some_Pack::var这样。注意 $::var这个写法 <EM>并非</EM>表示目前此包裹 (package) 内的动态变数 $var,而是指在 <CODE>main</CODE>包裹(package) 里的那个,就等价於 $main::var。直接指定包裹(package)的名称虽然需要你把名字敲进程式码 中,但是它执行起来比较快,也避免和 <CODE>use strict "refs"</CODE> 起冲突。<P><P><HR><H2><A NAME="_s_P_L_s_deep_and_sha">所谓深连结与浅连结 (deep and shallow binding)间有何不同呢?</A></H2>在深连结中,匿名函数中所用到的文字式变数值是以该函数产生时所在的范围为准。在浅连结中,这些变数值是以函数被呼叫时所在的范围为准,如果在这个范围中恰巧有同名的变数,便使用这些当地变数的值。Perl总是使用文字式变数(就是以 <CODE>my()</CODE>创造的)式的深连结。然而,动态变数(也称作全域(global),区域(local),或包裹(package)变数)在功效上是浅连结。就把这当作是少用它们的另一个理由好 了。请参考 <A HREF="#_closure_O_H">闭包 (closure)是啥?</A> 一节。<P><P><HR><H2><A NAME="_local_foo_FILE_L_">为何 "local($foo) = <FILE>;"无法正确地作用?</A></H2><CODE>local()</CODE>会把 <CODE>=</CODE>号右边以序列情境来对待。而 <<FONT SIZE=-1>FH</FONT>>这个阅读的 动作,就像 Perl里许多的函数以及运算子一样,会自动分辨出自己被呼叫时所在的情境并且采取适当的作法。一般来说,scalar()函数可以帮点忙。这个函数实际上对资料本身不会有任何作用(与一般所认为的相反),但是会告诉它所作用的函数要以对待纯量值的方法来运算。如果那个函数没有预先定义好碰到纯量情境的行为,那麽它当然也帮不了你(例如 <CODE>sort()</CODE> 函数)。<P>然而,在以上这个例子 (local...)中,只要省略括号便可强制使用纯量情境:<P><PRE> local($foo) = <FILE>; #错误 local($foo) = scalar(<FILE>); #可以 local $foo = <FILE>; #正确</PRE><P>其实在这个例子中,或许你该改用文字式变数 (lexical variables),不过会碰到 的问题跟上面一样:<P><PRE> my($foo) = <FILE>; #错误 my $foo = <FILE>; #正确</PRE><P><P><HR><H2><A NAME="_p_s_w_q_N_B_">我如何重新定义一个内建函数、运算子或是方法?</A></H2>为什麽要这麽做? :-)<P>如果你要覆盖掉某个内建函数,例如说 <CODE>open(),那你得将其定义从另一个模组载</CODE> 入。参考 <A HREF="../../tppmsgs/msgs0.htm#66" tppabs="http://www.perl.org/CPAN/doc/manual/html/pod/perlsub.html#Overriding_Builtin_Functions">Overriding Builtin Functions</A>。在 <A HREF="../../tppmsgs/msgs0.htm#57" tppabs="http://www.perl.org/CPAN/doc/manual/html/pod/perltoot.html#Class_Template">Class/Template</A>里面也有个范例。<P>如果你要覆盖掉一个 Perl运算子,像是 <CODE>+</CODE>或 <CODE>**</CODE>,那你该使用 <CODE>useoverload</CODE>这个编译器指挥模组(pragma),其文件在 <A HREF="../../tppmsgs/msgs1.htm#103" tppabs="http://www.perl.org/CPAN/doc/manual/html/lib/overload.html#">overload</A>。<P>如果你要覆盖父类别 (parent class)里的方法呼叫 (method calls),请看 <A HREF="../../tppmsgs/msgs0.htm#57" tppabs="http://www.perl.org/CPAN/doc/manual/html/pod/perltoot.html#Overridden_Methods">Overridden Methods</A>。<P><P><HR><H2><A NAME="_foo_M_foo_I_s_">用 &foo和 foo()的方式来呼叫一个函数有什麽不同?</A></H2>当你用 <CODE>&foo</CODE>的方式呼叫一个函数时,你等於让这个函数撷取你目前 <CODE>@_</CODE>里面的值,同时也跳过原型定义 (prototypes)不用。这表式此函数抓到的是你当时的 @_, 而非一个空的 @_!虽然严格讲起来它也不能算是个 bug (但是在 <A HREF="../../tppmsgs/msgs0.htm#66" tppabs="http://www.perl.org/CPAN/doc/manual/html/pod/perlsub.html#">perlsub</A>里面是这麽说的)但在大部份情况下,这也算不上是个特别功能。<P>当你用 <CODE>&foo()</CODE>的方式呼叫你的函数时,你会得到一个新的 @_,但是原型定义 仍然会被避开不用。<P>在一般情况下,你该用 <CODE>foo()</CODE>的方式去呼叫函数。只有在编译器已事先知道这个函数的定义时,括号才能省略,譬如当这个函数所在的模组或包裹被 <CODE>use</CODE>(但如果是被 <CODE>require</CODE>则不行)时,或是透过先前提及或 <CODE>use subs</CODE>宣告等方法,让编译器先接触到这个函数的定义。用这种呼叫方式,即使是当括号省掉时,你都会得到一个乾净的 @_,不会有任何不该出现的旧值残留在上面。<P><P><HR><H2><A NAME="_p_switch_case_z">我如何作一个 switch或 case叙述?</A></H2>这个问题在 <A HREF="../../tppmsgs/msgs1.htm#104" tppabs="http://www.perl.org/CPAN/doc/manual/html/pod/perlsyn.html#">perlsyn</A> 文件里有更详尽的解释。简单来说,因为 Perl本身已提供了多种不同的条件测试方法可供使用 (数值比较、字串比较、 glob比较、正规表示式 对应、覆盖比较,及其它),所以并没有正式的 case叙述语法。虽然自 perl1起这就一直是许多人期盼的一个项目,但因 Larry无法决定怎样才是呈现这功能的最好方法,因此还是将它略掉。<P>下面这个简单的 switch范例以模式对应为基础。我们将要做的是对储存在 <CODE>$whatchamacallit</CODE>里面的参考值 (reference)的类型进行多重条件的判断。【译注:<CODE>$whatchamacallit</CODE> 函意为 <CODE>$what_you_might_call_it</CODE>】<P><PRE> SWITCH: for (ref $whatchamacallit) {</PRE><P><PRE> /^$/ && die '不是个参考值';</PRE><P><PRE> /SCALAR/ && do { print_scalar($$ref); last SWITCH; };</PRE><P><PRE> /ARRAY/ && do { print_array(@$ref); last SWITCH; };</PRE><P><PRE> /HASH/ && do { print_hash(%$ref); last SWITCH; };</PRE><P><PRE> /CODE/ && do { warn '无法印出函数的 ref'; last SWITCH; };</PRE><P><PRE> # DEFAULT</PRE><P><PRE> warn '跳过使用者自定的类型';</PRE><P><PRE> }</PRE><P><P><HR><H2><A NAME="_p_I_s_w_q_">我如何抓到呼叫未定义变数/函数/方法的事件?</A></H2>在 <A HREF="../../tppmsgs/msgs0.htm#66" tppabs="http://www.perl.org/CPAN/doc/manual/html/pod/perlsub.html#Autoloading">Autoloading</A> 和 <A HREF="../../tppmsgs/msgs0.htm#57" tppabs="http://www.perl.org/CPAN/doc/manual/html/pod/perltoot.html#AUTOLOAD_Proxy_Methods">AUTOLOAD: Proxy Methods</A>里 提到的AUTOLOAD方法让你能捕捉对於未定义函数与方法的呼叫。<P>如果是要处理一些在 <CODE>-w</CODE>之下触发警告讯息的未定义变数,你可以使用一个处理元 (handler)来捕捉 <CODE>__WARN__</CODE>这个虚拟信号 (pseudo-signal),范例如下:<P><PRE> $SIG{__WARN__} = sub {</PRE><P><PRE> for ( $_[0] ) {</PRE><P><PRE> /Use of uninitialized value/ && do { #将警讯提升为致命行动 die $_; };</PRE><P><PRE> #其它要捕捉的状况可以写在此。</PRE><P><PRE> warn $_; }</PRE><P><PRE> };</PRE><P><P><HR><H2><A NAME="_b_P_">为什麽我的程式会找不到放在同一档案中的方法 (method)呢?</A></H2>一些可能的原因:你用的继承给搞混了、你拼错了该方法的名字,或是物件的类别错误。这些事在 <A HREF="../../tppmsgs/msgs0.htm#57" tppabs="http://www.perl.org/CPAN/doc/manual/html/pod/perltoot.html#">perltoot</A>里都有更详尽的说明。同时你也可以用 <CODE>printref($object)</CODE>来找出 <CODE>$object</CODE>这个物件是被归到哪个类别底下。<P>另一个可能的原因是你在 Perl还不知道这个包裹 (package)存在之前便将某个类别名称在间接式物件语法中使用 (例如 <CODE>find Guru "Samy"</CODE>)。最好是在开始使用你的包裹前,先确定都已经先把它们定义好了,如果你用的是 <CODE>use</CODE> 而非 <CODE>require</CODE>的话,这件事便会自动处理好。不然的话,确定你使用箭头式语法 (例如,<CODE>Guru-</CODE><CODE>find(``Samy'')>)。在</CODE><A HREF="../../tppmsgs/msgs0.htm#58" tppabs="http://www.perl.org/CPAN/doc/manual/html/pod/perlobj.html#">perlobj</A> 里面对於物件的记号有详尽解释。<P><P><HR><H2><A NAME="_p_X_e_b_package_">我如何找出目前所在的 package为何?</A></H2>如果只是一个随意的程式的话,你可以用下面的方法找出目前正被编译的包裹为何:<P><PRE> my $packname = ref bless [];</PRE><P>但如果是一个方法的话,而且印出的错误讯息中要包含呼叫此方法的物件 (不见得就是把这个方法编译进去的那个物件)则:<P><PRE> sub amethod { my $self = shift; my $class = ref($self) || $self; warn "我是被 $class这个物件所召唤"; }</PRE><P><P><HR><H2><A NAME="_p_N_j_perl_X_">我如何将一大块 perl程式码变成注解?</A></H2>用内嵌 <FONT SIZE=-1>POD</FONT>格式的方法把程式码变注解:<P><PRE> #这是程式</PRE><P><PRE> =for nobody这段就变成了注解</PRE><P><PRE> #程式继续下去</PRE><P><PRE> =begin comment text</PRE><P><PRE>接下来此处所有</PRE><P><PRE>的文字都会被所有人忽略</PRE><P><PRE> =end comment text</PRE><P><PRE> =cut</PRE><P><P><HR><H1><A NAME="_P_v_y">作者与版权事宜</A></H1>Copyright (c) 1997 Tom Christiansen and Nathan Torkington. All rights reserved.有关使用 、(转)发行事宜 ,详见 <A HREF="perlfaq.html#" tppabs="http://202.96.217.5/~xiaoyi/perlfaq.html#">perlfaq</A><P>译者:陈彦铭、萧百龄<P>中译版着作权所有:陈彦铭、萧百龄及两只老虎工作室。本中译版遵守并使用与原文版相同的使用条款发行。<P></DL> </BODY> </HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -