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.

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章