[PERL] 12- 副程式@新精讚

文章推薦指數: 80 %
投票人數:10人

此外副程式擺放的叫用順序沒有關係,因為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-變數的視界



請為這篇文章評分?