六、子程序的引用 perl中子程序的引用与C中函数的指针类似,构造方法如下: $pointer_to_sub = sub {... declaration of sub ...}; 通过所构造的引用调用子程序的方法为: &$pointer_to_sub(parameters);
·子程序模板 子程序的返回值不仅限于数据,还可以返回子程序的引用。返回的子程序在调用处执行,但却是在最初被创建的调用处被设置,这是由Perl对Closure处理的方式决定的。Closure意即如果你定义了一个函数,它就以最初定义的内容运行。(Closure详见OOP的参考书)下面的例子中,设置了多个错误信息显示子程序,这样的子程序定义方法可用于创建模板。
#!/usr/bin/perl sub errorMsg { my $lvl = shift; # # define the subroutine to run when called. # return sub { my $msg = shift; # Define the error type now. print "Err Level $lvl:$msg\n"; }; # print later. } $severe = errorMsg("Severe"); $fatal = errorMsg("Fatal"); $annoy = errorMsg("Annoying");
&$severe("Divide by zero"); &$fatal("Did you forget to use a semi-colon?"); &$annoy("Uninitialized variable in use"); 结果输出如下:
Err Level Severe:Divide by zero Err Level Fatal:Did you forget to use a semi-colon? Err Level Annoying:Uninitialized variable in use 上例中,子程序errorMsg使用了局域变量$lvl,用于返回给调用者。当errorMsg被调用时,$lvl的值设置到返回的子程序内容中,虽然是用的my函数。三次调用设置了三个不同的$lvl变量值。当errorMsg返回时,$lvl的值保存到每次被声明时所产生的子程序代码中。最后三句对产生的子程序引用进行调用时$msg的值被替换,但$lvl的值仍是相应子程序代码创建时的值。 很混淆是吗?是的,所以这样的代码在Perl程序中很少见。 七、数组与子程序 数组利于管理相关数据,本节讨论如何向子程序传递多个数组。前面我们讲过用@_传递子程序的参数,但是@_是一个单维数组,不管你传递的参数是多少个数组,都按序存贮在@_中,故用形如my(@a,@b)=@_; 的语句来获取参数值时,全部值都赋给了@a,而@b为空。那么怎么把一个以上的数组传递给子程序呢?方法是用引用。见下例:
#!/usr/bin/perl @names = (mickey, goofy, daffy ); @phones = (5551234, 5554321, 666 ); $i = 0; sub listem { my ($a,$b) = @_; foreach (@$a) { print "a[$i] = " . @$a[$i] . " " . "\tb[$i] = " . @$b[$i] ."\n"; $i++; } } &listem(\@names, \@phones); 结果输出如下:
a[0] = mickey b[0] = 5551234 a[1] = goofy b[1] = 5554321 a[2] = daffy b[2] = 666
注意: 1、当想传递给子程序的参数是多于一个的数组时一定要使用引用。 2、一定不要在子程序中使用形如 (@variable)=@_; 的语句处理参数,除非你想把所有参数集中到一个长的数组中。 八、文件句柄的引用 有时,必须将同一信息输出到不同的文件,例如,某程序可能在一个实例中输出到屏幕,另一个输出到打印机,再一个输出到记录文件,甚至同时输出到这三个文件。相比较于每种处理写一个单独的语句,可以有更好的实现方式如下: spitOut(\*STDIN); spitOut(\*LPHANDLE); spitOut(\*LOGHANDLE); 其中子程序spitOut的代码如下:
sub spitOut { my $fh = shift; print $fh "Gee Wilbur, I like this lettuce\n"; } 注意其中文件句柄引用的语法为\*FILEHANDLE。
|