sub
關鍵字開頭,表示聲明一個子程序&SUB_NAME()
的方式調用SUB_NAME子程序,&
有時候能夠省略,括號有時候也能夠省略。具體的規則見後面sub mysub { $n += 1; print "\$n is: $n","\n"; } &mysub; print "\$n is: $n","\n";
sub mysub { $n += 2; print "hello world\n"; $n + 3; } $num = ⊂
這裏的&sub
有返回值,它的返回值是最後執行的語句$n+3
,並將返回值賦值給$num
,因此$num
的值爲5。html
若是把上面的print做爲最後一句:python
sub mysub { $n += 2; $n + 3; # 這不是返回值 print "hello world\n"; # 這是返回值 } $num = ⊂
上面的print纔是子程序的返回值,這個返回值是什麼?這是一個輸出語句,它的返回值爲1,表示成功打印。這個返回值顯然沒什麼用。因此,子程序最後執行的語句必定要當心檢查。shell
那上面的$n+3
的結果是什麼?它的上下文是void context,相加的結果會被丟棄。數組
子程序還能夠返回列表。安全
($m,$n)=(3,5); sub mysub { $m..($n+1); } @arr=&mysub; print @arr; # 輸出3456
return
子句來返回值。固然,若是這個返回語句是最後一行,就能夠省略return# 返回一個偶數 $n=20; sub mysub { if ($n % 2 == 0){ return $n; } $n-1; # 等價於 return $n-1; } $oushu=&mysub; print $oushu,"\n";
Perl子程序除了能夠直接操做全局變量,還能夠傳遞參數。例如:函數
&mysub(arg1,arg2...); &mysub arg1,arg2...;
至於何時能夠省略括號,後面再解釋。測試
@_
中@_
是數組,就可使用$_[index]
的方式引用數組中的各元素,也就是子程序的各個參數@_
數組只在每一個子程序執行期間有效,每一個子程序的@_
都互不影響。子程序執行完成,@_
將復原爲原來的值# 返回最大值 @_=qw(perl python shell); # 測試:先定義數組@_ sub mysub { if($_[0] > $_[1]){ $_[0]; }else{ $_[1]; } } $max = &mysub(10,20); print $max,"\n"; print @_; # 子程序執行完,@_復原爲qw(perl python shell)
若是上面的子程序給的參數不是兩個,而是3個或者1個(&mysub(10,20,30);
、&mysub(10);
)會如何?由於參數是存在數組中的,因此給的參數多了,子程序用不到它,因此忽略多出的參數,若是給的參數少了,那麼缺乏的那些參數被引用時,值將是undef。code
因此,在邏輯上來講,參數多少不會影響子程序的錯誤,但結果可能會受到一些影響。但能夠在子程序中判斷子程序的參數個數:htm
if(@_ != 2){ # 若是參數個數不是2個,就退出 return 1; }
這裏的比較是標量上下文,@_
返回的是參數個數。blog
通常狀況下,調用咱們自定義的子程序時,都使用&
符號,有時候還要帶上括號傳遞參數。
&mysub1(); &mysub2; &mysub3 arg1,arg2; &mysub4(arg1,arg2);
但有時候,&
符號和括號是能夠省略的。主要的規則是:
&
也能夠不省略&
&
的狀況比較少。基本上,只要子程序名稱不和內置函數同名,或者有特殊需求時(如須要明確子程序的名稱時,如defined(&mysub)
),均可以省略&
&
、有參數傳遞的狀況下,省略括號&subname(arg1,arg2)
,即不省略&
和括號&subname
&
的調用方式是比較古老的行爲,雖然安全。但直接使用括號調用也基本無差異,但卻更現代,因此建議用func()的方式調用自定義的子程序sub mysub{ print @_,"\n"; } # 先定義了子程序 mysub; # 正常調用 mysub(); # 正常調用 mysub("hello","world3"); # 正常調用 mysub "hello","world4"; # 正常調用 &mysub; # 安全的調用 &mysub("hello","world6"); # 安全的調用 &mysub "hello","world7"; # 本調用錯誤,由於使用了&,且有參數
上面是先定義子程序,再調用子程序的。下面是先調用子程序,再定義子程序的。
mysub; # 本調用無括號,不報錯,當作內置函數執行,但無此內置函數,因此忽略 mysub(); # 有括號,不報錯 mysub("hello","world3"); # 有括號,不報錯 mysub "hello","world4"; # 無括號,本調用錯誤 &mysub "hello","world7"; # 本調用錯誤 &mysub; # 安全的調用 &mysub("hello","world6"); # 安全的調用 sub mysub{ print @_,"HELLO","\n"; }
若是子程序名稱和內置函數同名,則不安全的調用方式總會優先調用內置函數。
my關鍵字能夠聲明局部變量、局部數組。它能夠用在任何類型的語句塊內,而不限於sub子程序中。
sub mysub { my $a=0; # 一次只能聲明一個局部目標 my $b; # 聲明變量,初始undef my @arr; # 聲明空數組 my($m,$n); # 一次能夠聲明多個局部目標 ($m,$n)=@_; # 將函數參數賦值給$m,$n my($x,$y) = @_; # 一步操做 } foreach my $var (@arr) { # 將控制變量定義爲局部變量 my($sq) = $_ * $_; # 在foreach語句塊內定義局部變量 }
在my定義局部變量的時候,須要注意列表上下文和標量上下文:
@_=qw(perl shell python); my $num = @_; # 標量上下文 my (@num) = @_; # 列表上下文 print $num,"\n"; # 返回3 print @num,"\n"; # 返回perlshellpython
在Perl中,除了my能夠修飾做用域,還有local和our也能夠修飾做用域,它們之間的區別參見:Perl的our、my、local的區別。
my關鍵字是讓變量、數組、哈希私有化,state關鍵字則是讓私有變量、數組、哈希持久化。注意兩個關鍵字:私有,持久化。
使用state關鍵字聲明、初始化的變量對外不可見,但對其所在子程序是持久的:每次調用子程序後的變量值都保存着,下次再調用子程序會繼承這個值。
這個特性是perl 5.10版才引入的,因此必須加上use 5.010;
語句才能使用該功能。
use 5.010; $n=22; sub mysub { state $n += 1; print "Hello,$n\n"; } &mysub; # 輸出Hello,1 print $n,"\n"; # 輸出22 &mysub; # 輸出Hello,2 print $n,"\n"; # 輸出22
固然,若是在子程序中每次都用state將變量強制初始化,那麼這個變量持久與否就無所謂了,這時用my關鍵字的效果是同樣的。
use 5.010; sub mysub { state $n=0; print "hello,$n","\n"; } &mysub; &mysub; &mysub;
state除了能夠初始化變量,還能夠初始化數組和hash。但初始化數組和hash的時候有限制:不能在列表上下文初始化。
use 5.010; sub mysub { state $n; # 初始化爲undef state @arr1; # 初始化爲空列表() state @arr2 = qw(perl shell); # 錯誤,不能在列表上下文初始化 }
由於perl中支持先定義子程序再調用,也支持先調用再定義的方式。不一樣的調用方式有可能會有區別。
例如:
#!/usr/bin/env perl -w use strict; # do_stuff(1); # (1).在定義的前面 { my $last = 1; sub do_stuff { my $arg = shift; print $arg + $last; } } do_stuff(1); # (2).在定義的後面
上面在不一樣的位置調用子程序do_stuff(1)
,但只有第二種方式是正確的,第一種方式是錯誤的。
緣由在於my定義的變量是詞法做用域變量,先不用管詞法做用域是什麼。只須要知道my定義的變量是在程序編譯期間定義的好的,可是賦值操做是在程序執行期間進行的。而子程序sub的名稱do_stuff是沒法加my關鍵字的,因此perl中全部的子程序都是全局範圍可調用的。子程序的調用是程序執行期間的。
因此上面的程序中,整個過程是先在編譯期間定義好詞法變量$last
(但未賦值初始化),子程序do_stuff。而後開始從程序頭部往下執行:
當執行到(1)的位置處也就是調用子程序,這個子程序中引用了變量$last
,但$last
至今未賦值,因此會報變量未初始化的錯誤。
若是沒有(1),那麼從上往下執行將首先執行到my $last = 1
,這表示爲已在編譯期間定義好的變量賦值。而後再繼續執行到(2)調用子程序,但子程序引用的$last
已經賦值初始化,因此一切正常。
在perl中的子程序是在編譯期間定義好的,仍是執行期間臨時去定義的,目前我我的還不是太肯定,按照perl的做用域規則,它應該是在執行期間臨時去定義的。但不管如何,它先定義仍是後定義,都不影響對變量做用域的判斷。