Perl Subroutine Prototype的作用

      Perl Subroutine Prototype乍看之下是Perl提供了为Subroutine严格定义输入参数类型的一种途径。我们来看一下它的大致用法:

 

 

sub only_one_scalar_param($) {

}
only_one_scalar_param 1;         #正确
only_one_scalar_param(1);        #正确
only_one_scalar_param(1, 2);    #编译期间报错

 

 

要让Perl Subroutine Prototype能够正常工作,有如下几个条件

 

  1. subroutine的申明或者定义需要在编译期间可见,通俗点讲就是要在调用之前。
  2. 旧的Perl subroutine的调用是在subroutine前加上&,在加上&的情况下,Prototype也不起作用。
#定义在调用之后

only_one_scalar_param(1);          #正确
only_one_scalar_param(1, 2);      #正确,prototype没起作用

only_one_scalar_param 1;          #编译期间报错

sub only_one_scalar_param($) {

} 
 

 

sub only_one_scalar_param($) {
}
&only_one_scalar_param 1;         #正确
&only_one_scalar_param(1);        #正确
&only_one_scalar_param(1, 2)    #正确,prototype没起作用

 

 

      那Prototype的到底是用来做什么的呢? 在某些时候,Prototype确实可以用来检验输入参数(如最一开始的例子),并在编译期间就提示错误信息,但是实际上Prototype并不是如通常想象的那样,下面看一个例子

 

 

sub only_one_scalar_param($) {
       my( $value ) = @_;
       print "$value\n";
}

only_one_scalar_param(10);              #输出的是10
only_one_scalar_param(qw/1 2 3/);   #传入的是个list。 ?!没报错,输出的是3

 

      第一次调用的输出结果很容易让人理解,不过为什么第二次不仅没有错误,而且还输出的是3呢? 

      因为prototype定义的第一个参数是一个scalar,因此当遇上qw/1 2 3/这个list时,就将其转换成了scalar,即该list的长度。

 

那Prototype到底有什么用?

 

1.  省略括号

 

 

my @results = myfunc 3, 5;
#相当于 my @results = myfunc(3, 5);

#如果定义了prototype
sub myfunc($);
my @results = myfunc 3, 5;
#相当于 my @results = (myfunc(3), 5);

 

 

 

sub no_param(); #不可以使用参数


 

 

2.  编写类似built-in function的函数样式

 

 

sub mypush(\@@) {
       my( $array_ref, @to_push ) = @_;
       push @{$array}, @to_push;
}

mypush @array, 1, 2, 3;

 

 

使用Prototype可以让我们写出类似built-in function的subroutine,这是使用prototype的主要目的

 

 perlsub 写道
Because the intent of this feature is primarily to let you define subroutines that work like built-in functions, here are prototypes for some other functions that parse almost exactly like the corresponding built-in.

 

 

在其他情况下,使用Prototype是危险的!

 

再来看一个例子

 

 

use List::Util qw( min max );

sub clip_to_range($$@) {
       my ($min, $max, @data) = @_;

       return map { max( $min, min($max, $_) ) } @data;
}

clip_to_range(1, 2, (5..10));  
#min是1, max是2,data是(5..10)

my $range_ref = [1, 2];    #独立定义了一个range
clip_to_range(@{$range_ref}, (5..10));   
#使用这个range, 想表达和上面一次调用相同的意思,但是...
#min是2, max是5,data是(6..10)

 

 

为什么min是2呢? 因为@{$range_ref}被当成了第一个scalar参数,被转换成了长度,所以是2。而max则应该是下一个参数,Perl就从(5..10)中把5当做了max,余下的(6..10)就作为data。

 

程序真正执行的和自己预期的不相同,往往容易导致产生了Bug但是查不出来,因此最好避免这种情况的发生。上面的这个例子正是《Perl Best Practices》中的一条:“Don't use subroutine prototypes.

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值