▲说明
1.子程序的名字只能以字母、数字和下划线组成,同时不能以数字开头。
2.调用子程序可在其名字前加上与号(&),表示调用动作。
3.子程序名属于独立的名字空间,Perl不会把&fred和$fred搞混,因为它们分属于不同的命名空间。
定义子程序
▲定义子程序的方法
先用关键字sub开头,再写上子程序名,然后写上花括号,封闭在花括号里的代码块就是子程序的主体。
sub marine{ $n += 1; #全局变量$n print "Hello, sailor number $n! "; }
NOTE:
1.子程序可以被定义在程序中的任意位置,放在文件的开头、结尾都可以。
2.子程序的定义是全局的。
3.加入定义了两个重名的子程序,后面的子程序会覆盖前面的。
4.可以在子程序中使用任何全局变量。
调用子程序
▲
子程序名前加上与号(&)就表示调用这个子程序,也叫呼叫子程序。
&marine; #打印 Hello, sailor number 1! &marine; #打印 Hello, sailor number 2! &marine; #打印 Hello, sailor number 3! &marine; #打印 Hello, sailor number 4!
返回值
▲
在Perl中,所有子程序都有一个返回值,但并非所有返回值都有用,这要看具体进行的是什么操作。
子程序执行过程中最后一次运算的结果,不管它是什么,会被自动当作返回值。
sub sum_of_fred_and_barney{ print "I love u more than yesterday, but less than tomorrow. "; $fred + $barney; #这就是返回值 } $fred = 3; $barney = 4; $wilma = &sum_of_fred_and_barney; #$wilma为7 print "$wilma is $wilma. "; $betty = 3 * &sum_of_fred_and_barney; #$betty为21 print "$betty is $betty. ";
注意:
1.在子程序里添加额外的程序代码时,要注意检查最后执行的表达式是哪一个,确认它是你需要的返回值。
sub sum_of_fred_and_barney{ print "I love u more than yesterday, but less than tomorrow. "; $fred + $barney; print "Hey, I'm returning a value now! "; #糟糕! }
最后执行的语句不是加法运算,而是print语句,它的返回值通常是1,表示“成功输出信息”。
2.$fred + $barney相加的结果被丢弃了,启用警告信息时,会提示void context(空上下文),表示运算结果未被使用,既没有存储到变量里,也没有被任何函数使用。
3.“最后执行的表达式”的准确含义就是最后执行的表达式,而非程序的最后一行代码。
参数
▲
传递参数列表到子程序,在子程序调用的后面加上括在括号内的列表表达式即可。
$n = &max(10,15); #包含两个参数的子程序调用
▲
Perl会自动将参数列表化名为特殊的数组变量@_,该列表在子程序执行期间有效。
第一个参数存储在$_[0],第二个参数存储在$_[1],依此类推。
sub max{ if($_[0] > $_[1]){ $_[0]; }else{ $_[1]; } }
缺点:
1.一堆下标,程序不雅观。
2.不提示接收几个参数。
▲
@_变量是子程序的私有变量,加入已经有了全局变量@_,则该变量在子程序调用前会先被存起来,并在子程序返回时恢复原本的值。
子程序中的私有变量
▲
可以使用my 操作符来创建私有变量,我们称之为词法变量。
my ($m, $n) = @_;
变长参数列表
▲
把长度不限的列表作为参数传递给子程序,解决办法:
1.检查@_数组的长度来判断参数个数是否符合预期
sub max{ if(@_!=2){ ... } }
2.让子程序自动适应任意数目的参数
改进版的&max子程序:
$max_num = &max(3,5,10,4,6); sub max{ my $max_so_far = shift @_; foreach (@_){ if($_ > $max_so_far){ $max_so_far = $_; } } $max_so_far; }
用my声明的词法变量
▲
词法变量可以用在任何语句块内,并不仅限于子程序的语句块;
1.在if、while或foreach内使用词法变量
2.foreach的控制变量也可以声明为词法变量
foreach my $rock(qw/bedrock slate lava/){ ... }
注意:
1.词法变量的作用域受限于定义它的最内层语句块内,或文件内,只有语句块的代码才能使用这个词法变量。
2.my操作符不会更改变量赋值时的上下文。
my ($num) = @_; #列表上下文 my $num = @_; #标量上下文
3.在my操作符不加括号时,只能用来声明靠近的单个词法变量。
my $fred, $barney; #错,没声明$barney
my ($fred, $barney); #两个都声明了
4.最好对每个新变量都使用my声明,让它保持在自己所在的词法作用域内。
5.词法变量无法存续,语句块一结束,它的值就会被抛弃。
use strict编译指令
▲
use strict编译指令用于告诉Perl愿意接受更严格是限制,可以放在程序开头,或是任何需要强制使用约束规则的语句块或文件内。
▲
从Perl 5.12开始,如果使用编译指令使用最低Perl版本号的话,就相当于隐式使用约束指令。
use v5,12; #自动加载use strict编译指令
▲
此限制只适用于创建新的变量,Perl的内置变量(比如$_和@_)则完全不用事先声明。
return操作符
▲
作用:立即停止运行并从子程序内返回某个值。
my @names = qw/ fred barney betty dino wilma pebbles bamm-bamm /; my $result = &which_element_is("dino", @names); sub which_element_is{ my($what,@array) = @_; foreach(0..$#array){ #数组中所有元素的索引 if($what eq $array[$_]){ return $_; #一发现就提前返回 } } -1; #表示没找到符合条件的元素(可以省略return) }
NOTE:
1.return最常见的用法:立即返回某个值,而不再执行子程序的其余部分。
2.最后一行写成return -1也行,读起来更明朗,但因为是最后一行,可以省略return。
省略与号(&)
▲
1.Perl通过语法规则判断它只能是子程序调用,可以省略与号。
比如:将参数列表放进括号里,它就一定是子程序调用
my @cards = shuffle(@deck_of_cards);
注意:
假如这个子程序和Perl内置函数同名,为避免歧义,就必须使用与号调用。所以只能在没有同名内置函数的情况下省略与号。
2.如果Perl的内部编译器已经见过子程序的定义,可以省略与号,并且参数列表两边的括号都可以不写。
sub division{ $_[0]] / $_[1]; } my $quotient = division 355, 113;
非标量返回值
▲
子程序不仅可以返回标量值,如果在列表上下文中调用它,还可以返回列表值。
@c = &list_from_fred_to_barney;
持久化私有变量
▲
在子程序中用my操作符可以创建私有变量,但每次调用子程序时,这个私有变量都会被重新定义。因为词法变量无法存续,语句块一结束,它的值就会被抛弃。用state操作符声明的变量可以在子程序的多次调用期间保留之前的值,而其作用域仍局限在子程序内部。
▲
state是从Perl 5.10开始引入的。