第四章:子程序
子程序名由字母、数字和下划线组成,但是不能以数字开头。
有时候会以&(与号)开头。
用sub关键字来定义子程序名,子程序名(不包含“与号”)
sub marine { $n += 1; print "Hello, sailor number $n!\n"; }
|
Perl中任何情况下你都不需要对子程序进行事先声明。子程序定义是全局的。
假如你定义了两个重名的子程序,那么后面的那个子程序会覆盖掉前面的。
调用子程序:
在子程序名前面加上“与号”来调用它。
&marine;
sub marine { while ( $n < 10){ $n += 1; print "Hello, sailor number $n!\n"; } } print &marine;
|
返回值:
子程序被调用时一定是作为表达式,某个部分,即使该表达式的求值结果不会被用到。
所有的子程序都有一个返回值。子程序没有“有返回值”和“没有返回值”之分。但并不
是所有的Perl子程序都包含有用的返回值。
sub sum_of_fred_and_barney { print "Hey, you called the sum_of_fred_and_barney subroutine!\n"; $fred + $barney; #这就是返回值
}
$fred = 3; $barney = 4; $wilma = &sum_of_fred_and_barney; #$wailma为7
print "\$wilma is $wilma.\n"; $betty = 3 * &sum_of_fred_and_barney #$betty为21
print "\$betty is $betty.\n";
sub larger_of_fred_or_barney { if ( $fred > $barney ) { $fred; } else { $barney; } }
=================================================================== sub sum_of_fred_and_barney { print "Hey, you called the sum_of_fred_and_barney subroutine!\n"; $fred +$barney; #这不是返回值!
print "Hey, I'm returning a value now!\n"; #糟糕!这不是我要的结果
} 上面返回值通常是1,代表“输出成功”。
|
参数:
传递参数列表(argument list)到子程序里,只要在子程序调用的后面加上被括号圈引的列表表达式(list expression)就行了。
$n = &max(10, 15); #包含两个参数的子程序调用
参数列表将会传入子程序,让子程序随意使用。当然,得先将这个列表存在某处。Perl会自动将参数列表化名为特殊的数组变量@_,
sub max { #请比较它和子程序&larger_of_fred_or_barney的差异
if ( $_[0] > $_[1]) { $_[0]; } else { $_[1]; } } 你可以那么写,但是,这里的一堆下标让程序变得不雅观,而且难以阅读、编写、检查和调试。 $n = &max(10,15,27); #糟糕,因为这个子程序只接受两个参数,多余的参数会被忽略。参数不足会得到undef。
|
子程序中的私有变量:
默认情况下,Perl中所有的变量都是全局变量,也就是说。在程序里的任何地方都可以访问它们,但是你可以随时运用一个操作符来创建私有的记法变量(lexical variables)。这个操作符就是my:
sub max { my($m,$n); #该语句块中的新私有变量
($m, $n) = @_; #将参数赋值给变量
if ($m > $n) { $m } else {$n} #因为这里程序是写在一行的,所以不用";"。
} 这个变量也可以简化: my ( $m , $n ) = @_; #将保存在@_中的参数赋值给具体的变量。
在真实的Perl代码中,常常把更长的(任意长度的)列表作为参数传给子程序。这延续了Perl的理念”去除不必要的限制“; 当然,子程序可以很容易地能过检查@_数组的长度来确定参数的个数是否正确。比方说,我们可以将&max写成如下的形式,检查它的参数列表: sub max { if (@_ != 2) { print "WARNING! &max should get exactly two arguments!\n"; my($m,$n); #该语句块中的新私有变量
($m, $n) = @_; #将参数赋值给变量
if ($m > $n) { $m } else {$n} #因为这里程序是写在一行的,所以不用";"。
} 这个变量也可以简化: my ( $m , $n ) = @_; #将保存在@_中的参数赋值给具体的变量。
} 更好的&max子程序: $maximum = &max ( 3, 5, 10, 4, 6);
sub max { my ($max_so_far) = shift @_; #数组的第一个值,暂时把它当成最大值
foreach (@_) { #遍历数组@_中的其他元素
if ($_ > $max_so_far) { #当前元素比$max_so_far更大吗?
$max_so_far = $_; } } $max_so_far }
|
上面的程序代码使用了一般称为”高水线(high-water mark)“的算法:大水过后,在最后一波浪消退时,高水线会标出最高的水位。$max_so_far记录了高水线,也就是我们见过的最大数字。
第一行程序代码会对参数数组@_进行shift操作,并将得到的3(范例程序的第一个参数)存入$max_so_far变量,所以@_现在的内容为(5,10,4,6)因为3已被移走。现在最大的数字是3.也就是第一个参数。
然后foreach循环会遍历参数列表@_里其他的值。循环的控制变量默认为$_(别忘记了@_和$_没有任何关系。它们的名称相似纯属巧合。循环第一次执行时,$_是5,而if进行比较时看到$_比$max_so_far还大,所以$max_so_far会被设成5新的高水线。
阅读(589) | 评论(0) | 转发(0) |