定義子程序
Perl中有許多內置的系統函數,如chomp、sort、print等,每一個這樣的函數都可以實現各種不同的操作。Perl也可以讓用戶根據需要自己創(chuàng)建子程序,來實現各種特定操作。一個完整的子程序同Perl的內置函數或操作符一樣,由子程序名稱以及子程序的代碼所組成。子程序名屬于Perl標識符范疇,并擁有獨立的名字空間。子程序名應盡量不與Perl中自帶的操作符或函數同名,否則易引起混淆和錯誤。
定義子程序,即使用代碼說明這個子程序所要實現的操作。原則上,子程序可以被定義在程序中的任意位置。要定義一個子程序,使用關鍵字sub加上子程序名,后接用花括號圍住的代碼塊即可。例:
sub printy{print'Y'}??? #定義一個名為“printy”的子程序,其功能為輸出Y
sub sum{$n+$m}???? #定義一個子程序,其功能為計算$n與$m的和
調用子程序
當一個子程序在代碼中的任何位置被定義后,就可以在程序中被調用。使用與號“&”加上子程序名即可調用一個子程序。例:
&printy;???#調用printy子程序
與號是可以省略的,但必須滿足兩個條件:1.子程序在先前的代碼中已被定義。2.子程序名不能與Perl內置函數重名。如果能滿足上述的兩個條件,在調用子程序時就可以省略與號。例:
printy;???#省略&的調用
返回值
Perl中,所有的子程序都有一個返回值,即不存在無返回值的子程序,但并不是所有的子程序都包含有用的返回值。有的子程序用于計算,其返回值就可以為計算結果,而有的子程序的功能類似于操作符,其用來實現一些特定操作,這樣的子程序的返回值往往就是無用的。
子程序中最后一個被計算的表達式的返回值就是該子程序的返回值。最常見的作為返回值的代碼是自成一行的一個表達式。如一個運算式,或自成一行的一個變量,運算的結果或變量的當前值會作為返回值返回。例:
sub sum{$n+$m}??? #返回值是加法運算的結果
作為返回值的代碼也可以是一個賦值式。實際上,一個賦值式做了兩項工作,即先對右邊的表達式進行運算,并將運算結果返回,然后再將這個返回的結果賦值給左邊的內容。所以一個賦值式的返回值就是其右邊表達式的運算結果。例:
sub sum{$_=$n+$m}??? #返回值就是右邊加法運算的結果
子程序的返回值不一定是一個標量,其也可以是一個數組或列表。例:
sub list{"@n"}??? #子程序的返回值為一個內插的數組
參數
在子程序中不一定要使用存在于整個程序中的全局變量,這會造成很多的不便。而事實上,使用子程序參數才是子程序的實際用法。
子程序的參數為一個參數列表,這個列表書寫于調用子程序語句中子程序名之后。在子程序被調用時,Perl會自動將參數列表更名為特殊的數組@_,該數組變量僅在子程序運行期間有效。即類似于foreach循環(huán)的控制變量,在子程序被調用前,如果@_已有定義,那么@_會被存起來,并在子程序結束時恢復原來的值。這樣的性質保證了子程序遞歸等高級用法的實現,這里不詳細論述。
@_中的元素可供子程序執(zhí)行期間調用。為方便起見,建議在子程序的開頭將@_中的元素賦值到新的自定義變量中以便于子程序代碼的書寫和閱讀。這對于某些復雜的子程序尤為重要。
sub max{
????? ($n,$m)=@_;?????????? #將@_中的元素賦值給變量列表
????? if($n>$m){$n}else{$m}
}
print max($a,$b);?????????? #使用參數列表的子程序調用,($a,$b)會被自動化名為@_
子程序對參數列表長度的自適應
在真實的Perl代碼中,參數列表的長度往往是未知的,即是任意長度的。這就要求子程序能夠對任意長度的參數列表實現自適應,而不僅僅只適用于固定長度的參數列表。自適應的實現可以有各種靈活的方法,下文僅以高水線算法子程序為例,說明這個技巧:
sub max{
????? ($max,@n)=@_;
????? for(@n){$max=$_if$_>$max}
????? $max;
}
上例中,子程序首先將傳入參數賦值給兩個部分:參數列表的第一個元素賦值給一個作為臨時最大值的變量,余下部分賦值給一個數組。然后對這個數組中的每一個元素進行循環(huán)迭代,只要數組中的元素大于當前的臨時最大值,就把這個元素的值賦值給臨時最大值變量。這樣經過全部的迭代運算后,臨時最大值變量所存儲的值就是參數列表中的最大值。這個算法被稱為“高水線算法”。
上例中,使用foreach循環(huán)結構實現了對參數列表長度的自適應,即無論參數列表的長度是多少,foreach結構都能對其進行循環(huán)迭代,包括只有一個參數的情況和沒有參數的情況。
return操作符
類似于循環(huán)控制的last操作符,return操作符可以立即終止子程序并可以返回一個返回值。返回值即return的參數,該參數也可省略,從而只結束子程序而不返回任何值。例:
sub one{
????? for(0..$#_){return$_if$_[$_]==1}
????? -1;
}
上例中,使用foreach循環(huán)對參數列表的索引值列表0..$#_進行循環(huán)迭代,并取出@_中索引值對應的元素$_[$_]與1比較,只要該元素與1相等,就執(zhí)行return,返回這個索引值并立即結束子程序。如果進行完了全部的循環(huán)迭代仍未執(zhí)行過return,則將-1作為返回值返回。
私有變量
默認情況下,Perl中的所有變量都是全局變量,即這個變量在程序中的任何位置都可以訪問,且訪問到的都是同一個變量。到目前為止,所有例程序中使用的變量也都是全局變量。子程序中的代碼是一個相對封閉且獨立于外界的代碼塊。所以如果將其中的變量設定為子程序的私有變量,從而不受外界代碼的影響,這將大大提高子程序的穩(wěn)定性與代碼的易維護性。
Perl中,可以使用my操作符來創(chuàng)建私有變量,又稱為詞法變量或有限作用域變量。被創(chuàng)建的私有變量不受外界同名變量的影響,反之亦然,即在代碼塊中被創(chuàng)建的私有變量$n與外界的$n互不相干,這是完全無關的兩個變量。my操作符可以一次性聲明多個詞法變量,將多個需要聲明的詞法變量一起放入my后面的括號中,每個參數之間以逗號隔開即可。my聲明語句不一定要自成一行,也可以與賦值式等連用。
詞法變量可以被創(chuàng)建于程序的任何位置,包括直接創(chuàng)建于沒有任何語句塊的程序代碼中。詞法變量的作用域限定于定義它的最內層語句塊或文件,即被創(chuàng)建的詞法變量對于其所屬的最內層語句塊或文件來說是私有的,這個私有的詞法變量與外界的重名變量互不相干。例:
my($i,$j,@a)=@_;??? #一次性聲明三個詞法變量并賦值
使用my操作符聲明詞法變量又可以理解為新建一個或多個變量,因為是新建,所以每一次聲明詞法變量時,被聲明的變量都是新的,標量變量會被創(chuàng)建為undef,數組和哈希會被創(chuàng)建為空數組或空哈希。
my操作符的作用僅為聲明詞法變量,并不會改變被聲明的詞法變量所處的上下文。即在判斷上下文時,完全可以忽略my這個詞。例:
my$n=@n;?????#變量上下文
my($m)=@n;???#列表上下文
由于詞法變量具有使程序更為穩(wěn)定,通用性更強且易于維護等特點,所以建議所有的變量在使用前均進行聲明。
持久性私有變量
state操作符與my類似,是另一種用來聲明詞法變量的操作符,其可以聲明持久性私有變量。使用state聲明變量時,被聲明的變量只會在第一次聲明時進行初始化,然后state所在的聲明語句就會被Perl忽略,不會再次聲明并初始化這個變量。這樣的操作就不僅可以聲明變量私有,還可以在多次調用該變量期間保留變量值。這種只聲明一次而具有持久性的變量就稱為持久性私有變量。state操作符是Perl 5.10的新功能,所以使用時要啟用5.10版本。例:
use 5.010;???????????? #啟用Perl 5.10
sub plus{state$n++}??? #聲明$n為持久性私有變量
plus;plus;
print plus;???????????? #三次調用子程序,并輸出最終返回值
如上例所見,$n在三次調用子程序期間沒有被初始化,而是保留了每一次運算的結果。上例中的雙目賦值操作符也可以用前置自增代替:
sub plus{++state$n}??? #聲明一個持久性私有變量,然后對其進行前置自增
由于Perl語言自身的限制,在使用state聲明列表、數組或哈希類型的變量時,不能同時進行聲明和賦值操作,只能分開書寫,否則程序會報錯。在最新版本的Perl中,仍然無法使用這種寫法。例:
use 5.20.2;?????????? #啟用目前最新的Perl語言版本
state($n,$m)=@_;
state@n=qw/a b c/;??? #不能使用這兩種寫法。即不能同時聲明并賦值
可以將聲明語句與賦值語句分開書寫,例:
use 5.20.2;
state($n,$m,@i);??? #先單獨聲明持久性私有變量
($n,$m)=@_;
@i=qw/a b c/;????? #聲明與賦值分開操作
strict編譯指令
Perl是一門在語法及編程上限制較少的語言。但如果希望Perl能夠在語法上更加嚴格,遵循一些優(yōu)良的代碼風格時,就可以啟用strict編譯指令。從Perl 5.12開始,strict編譯指令將被自動啟用,所以如果啟用了5.12以上的版本,就相當于隱式打開strict編譯指令。例:
use strict;????#啟用strict編譯指令
use 5.20.2;???#隱式啟用strict編譯指令
啟用strict編譯指令最顯著的特點,就是會強制要求聲明每一個新變量,如果沒有聲明,則程序不會運行,并且會發(fā)出警告。例:
use strict;
$n=1;??????#由于啟用了strict編譯指令且此處沒有對變量進行聲明,所以程序不會運行并會發(fā)出警告
而正確的寫法為:
my$n=1;???#聲明這個新變量
strict的這種限制僅適用于程序中的新變量,對于Perl的內置變量,如默認變量$_,用于子程序參數的數組變量@_等,均無需聲明。另外,$a與$b也屬于Perl的內置變量,它們是sort函數的內置變量(詳見“高級排序”),所以這兩個變量也不在strict編譯指令的約束范圍內,且在實際的編程中,也不建議將這兩個變量當作普通變量使用。
櫻雨樓
完成于2016.1.12
最后修改于2016.1.30