[PERL] 12- 副程式@新精讚
文章推薦指數: 80 %
此外副程式擺放的叫用順序沒有關係,因為PERL是全部載完再編譯執行,下面兩個同義: ... sub p {. $_ = shift ;. print "$_\n" ; #10. $_ = shift ;.
[PERL]12-副程式
URLLink//n.sfs.tw/11707
2017-08-2522:50:43By張○○
PERL的副程式就是所謂的函數。
副程式的寫法
以sub開頭接著副程式的名稱
subfunction_name{
#副程式內容
return1;#副程式回傳,非必要
#在return後的指令是不會被執行的
}
和別的語言函式定義不太一樣,就是沒有小括號讓你傳參數進去。
要回傳結果可用return,這個指令非必要可省略。
在return後面的指令不會被執行。
副程式的叫用
&function_name;#前面加一個'&'
&function_name(12,34,56);#傳入值
&function_name(@arr);#傳入陣列
此外副程式擺放的叫用順序沒有關係,因為PERL是全部載完再編譯執行,下面兩個同義:
subp{...}
&p;#副程式在前
等同於
&p;#副程式在後
subp{...}
副程式的取值
副程式中要怎麼取得傳入的引數?
可以使用二種方法:1shift函數或2特殊陣列@_
使用shift
shift在陣列中有提過,是從陣列的最開始取出一個項目,取出後引數少1,再執行一次再少1...
&p(10,24,32);
subp{
$_=shift;
print"$_\n";#10
$_=shift;
print"$_\n";#24
$_=shift;
print"$_\n";#32
$_=shift;
print"$_\n";#Useofuninitializedvalue$_inconcatenation(.)orstringat..
}
上面的範例中,傳入3個引數,理應只能取用(shift)3次,若取用到第4次時,就出現錯誤。
眼尖的人也許會想到,shift這個是取出陣列最開頭的項目,後面應該接著陣列,可是範例中shift後並無接著陣列,為什麼能取出引數呢?原來預設傳入的引數會放到PERL的特殊變數@_中
使用@_
@_是預設副程式傳入的參數,若傳入的引數有3個,可以直接使用清單的方式指定。
&p(10,24,32);
subp{
($a,$b,$c)=@_;
print$a,$b,$c;#102432
print"\n";
}
某些情況你可能不知道使用者會傳入幾個參數,例如要算平均數,使用者可傳多個引數,這時用@_就最方便了
$avg=&avg(10,24,32,-15);
print$avg;
subavg{
$sum=0;
foreach(@_){
$sum+=$_;
}
return$sum/@_;
}
第1行叫用副程式avg,並傳入4個引數,回傳的結果設定給變數$avg,這裡故意把副程式的名稱和變數取名一樣,在PERL裡面這兩個是不相干的。
第6-8行對傳入的引數進行加總,迴圈的寫法應該不陌生了。
第9行直接把總和除以引數的個數,注意這裡把@當成純量時就是項目的個數(前面有提過)。
這個程式看似沒有問題,但還是有缺點,就是若使用者叫用時無傳入引數,在平均時因為@_=0(分母為0)則會出錯。
因此加了一個檢查而確保。
修正後的程式如下:
$avg=&avg;
print$avg;
subavg{
return0if@_==0;
$sum=0;
foreach(@_){
$sum+=$_;
}
return$sum/@_;
}
第5行檢查傳入引數為0,則直接回傳0。
傳入引數應該注意的問題
在PERL中會把傳入的所有引數都放到陣列@_之中,假如在引數中放入陣列會發生什麼事?來看看下面的範例:
傳入一個陣列
@a=(1,3,4);
&avg(@a);
subavg{
print"@_";#134
}
第5行沒問題的印出傳入的@a
傳入二個陣列
如果傳入二個或多個陣列,結果就不會是你要的
@a=(1,3,4);
@b=(6,7,8);
&avg(@a,@b);
subavg{
print"@_";#134678
}
還記得在08-陣列#2--操作提過,PERL的陣列全是一元的,如果把多個陣列放到引數後,所有的引數都會被攤平成為一個@_,如果使用shift取引數和你想的不一樣。
@a=(1,3,4);
@b=(6,7,8);
&avg(@a,@b);
subavg{
@p=shift;
@q=shift;
print"@p\n";#1
print"@q\n";#3
}
第6-7行原本以為可以取得原本傳入的2個陣列引數,結果竟然是被攤平了,只取取得了1和3。
所以知道多個陣列當成引數時,都自動被合成一個一維的陣列。
同時傳入變數和陣列
同時傳入變數和陣列的話,變數要先寫,陣列放最後,並用清單的方式就能取出資料。
下面的例子把變數$z放最後一個引數,並觀察它被陣列@r吃掉了。
$x=123;$y=555;$z='ABC';
@b=(6,7,8);
&avg($x,$y,@b,$z);
subavg{
($p,$q,@r,$z)=@_;
print"$p\n";#123
print"$q\n";#555
print"@r\n";#678ABC
print"$z\n";#Useofuninitializedvalue$zinconcatenation(.)orstringat..
}
第9行@r陣列把後面的引數全部收攏當成他的。
第10行在陣列@r後的$z取不到資料,出了錯。
結論
1.無論傳入幾個變數或陣列,都會被合併成一個一維陣列@_
2.傳入的引數有陣列的話,要放在最後一個引數
3.使用清單取得傳入的引數,陣列要放最後一個,剩下的引數全會被陣列收走。
4.用shift一次只能取一個項目,不是一個引數。
學會了副程式的寫法後,我們可能會寫很多副程式並重覆的利用,最好的方法就是存成一個個只有副程式存在的檔案,叫作「函式庫」。
使用函式庫
假設先把副程式存成一個檔案叫mylib.pl作為函式庫,裡面暫時只放一個剛才寫的求平均數副程式。
mylib.pl
subavg{
return0if@_==0;
$sum=0;
foreach(@_){$sum+=$_;}
return$sum/@_;
}
1;
接下來在我們要執行的主程式中,使用require保留字把我們函式庫mylib.pl載入
run.pl
#!/usr/local/bin/perl-w
require"mylib.pl";
print&avg(3,5,6,8,11);
第2行使用require載入mylib.pl這個函式庫
執行
$./run.pl
6.6
在上面的例子中,也許讀者注意到mylib.pl這裡面最後多了一個數字1加上分號:1;
感覺非常的奇怪,這是什麼東西?如果好奇把他拿掉,就出現這樣的錯誤:
mylib.pldidnotreturnatruevalueat./run.plline2.
首先要說PERL在某方面是很怪異的語言,1;的意思其實是return1;說真的讓你回傳一個1不是很莫名其妙嗎?那我寫成2;可不可以?這次我不和你說結果你自己試!
但為什麼要寫一個1;在最後面?這是因為require+檔案時它需要一個true的回應:好吧,那就給他一個1;,這個東西在後面講到[PERL]18-套件及模組時會再次出現。
這篇先介紹副程式的基本操作,使用副程式可以讓你的程式看起來更加簡潔,下一篇會說明如何建立自己的函式庫及變數的「視界」。
上一篇11-雜湊的範例
回到目錄01-撰寫第一隻PERL程式
下一篇13-變數的視界
延伸文章資訊
- 1Subroutines - Perl 101
Subroutines. Retrieving arguments to a subroutine with shift. A subroutine's arguments come in vi...
- 2Perl shift Function - Tutorialspoint
Perl shift Function, This function returns the first value in an array, deleting it and shifting ...
- 3shift in Perl - Perl Maven
The shift function in Perl will remove the first value of the array passed to it and return it. ....
- 4What does shift() do in Perl? - Stack Overflow
shift() is a built in Perl subroutine that takes an array as an argument, then returns and delete...
- 5副程式 - 程式語言教學誌FB, YouTube: PYDOING: Perl 入門指南
副程式(subroutine) 是一種功能性的模組,可以將程式(program) 分割成小部分,藉由呼叫方法安排執行順序 ... #!/usr/bin/env perl sub big { $a...