megnlingling 发表于 2017-5-17 11:47:27

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能够正常工作,有如下几个条件


[*]subroutine的申明或者定义需要在编译期间可见,通俗点讲就是要在调用之前。
[*]旧的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 = ;    #独立定义了一个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.”
页: [1]
查看完整版本: Perl Subroutine Prototype的作用