1.定义子程序
使用sub关键字定义 ; 子程序名和标识符同要求, 但是有的特殊的可以用 &符号; 子程序是全局的, 不需要再使用前声明; 重名函数后者覆盖前者.
sub roger{ $n += 1; #全局变量$n print "Hello , sailor number $n!\n"; } &roger # 前面加&来调用, 不过没加好像也能调用.
返回值: 在子程序执行过程中会不断运算, 而最后一次运算的结果(不管是什么)都会被当成子程序的返回值. 最后一行作为返回值可以省略逗号
2.Perl函数参数
参数传递: Perl维护一个特殊数组变量 @_ , 这个变量在子程序执行期间有效, 子程序可以访问这个数组, 递归调用会有各自的 @_ , 因为Perl会自动保存和恢复
使用: 使用 $_[index] 来进行访问, 就想对一个数组 @roger , 可以使用 $roger[0] 来访问 @roger 的第一个元素一样, 可能是内部规定吧; 如果使用 @_[index] 访问也能得到正确结果, 但是会得到一个警告: Scalar value @_[0] better written as $_[0]
Perl中所有的变量都是全局变量, 在程序的任何地方都能访问它们, 但是随时可以使用(不仅仅是在子程序中) my 操作符(也称为词法变量)来创建私有的变量. 参数变量 @_ 就是子程序的默认私有变量. 特殊情况: 使用 &subname 调用子程序, 并且没有参数时, @_ 会从上下文中继承下来.
sub max{ my($m,$n) = @_; if($m > $n){$m}else{$n} } print &max(1,2)
my操作符会不改变赋值时的上下文; 不带括号时只能作用于一个变量, 多个变量要用 my()
@t = (1,2,3); my($roger) = @t; # 列表上下文 my $r = @t; # 标量上下文 print $roger; # 1 print $r; # 3
3. return操作符
虽然在子程序中可以不用return进行返回(默认返回最后一次计算结果), 但是可以用return立即返回; 单写一个return,不给任何参数, 在标量上下文中返回undef, 在列表上下文中返回空列表.
4. 子程序调用省略 & 号
如果编译器在调用子程序之前看到了子程序的定义, 或者Perl可以从语法识别它是子程序调用, 那么子程序据可以像内置函数一样在调用时直接使用名字. 但是建议都加上 & , 避免与内置函数重名.
sub mycount{ if($a < $b){ #访问全局变量 $a .. $b }else{ reverse $b .. $a } } $a = 10; # 在函数调用之前赋值 $b = 2; print &mycount
5.持久性私有变量--使用state操作符
# 使用全局变量的情况 sub roger { $n += 1; #每次调用都会讲全局变量 $n 增加1, 第一次使用的时候没有说明$n是全局变量, 但是根据结果可以知道在子程序里面定义的也是全局变量 } for($i=0;$i<10;++$i){ &roger() } print "$n\n";
# 使用私有变量的情况 use 5.010; sub roger { state $n = 0; # 持久性私有变量 $n $n += 1; } for($i=0;$i<10;++$i){ print &roger(); #输出 1 .. 10, 使变量在第一次调用roger()函数结束之后仍然保留,而如果用my就会被销毁 printf("\n"); } print $n; # undef
注意: 在 5.010中不能在列表上下文中初始化以下类型的state变量 state @array = qw(a b c); # wrong!