Perl Learning (4) —— 子程序

2011-01-25 wcdj

 

(1) 定义子程序和调用子程序
(2) 返回值
(3) 参数
(4) 子程序中的私有变量
(5) 长度可变的参数列表
(6) 关于词法(my)变量
(7) use strict编译命令
(8)  return操作符
(9) 省略“&”与号
(10) 非标量返回值 —— 返回列表值
(11) 持久性私有变量 —— 作用类似C中的static关键字

Perl也可以创建子程序(subroutines),也就是用户定义的函数。—— 让我们可以重复利用已有的代码。

(1) 定义子程序和调用子程序
使用关键字sub,子程序名(不包含“与号”)以及经过缩进的代码块(花括号中的内容),它们组成了子程序的主体。
注意:
[1] 子程序可以在程序的任意位置定义。
[2] 任何情况下你都不需要对子程序进行事先声明。
例如:

&func;# Hello, number 1! &func;# Hello, number 2! sub func { $n+=1;# 全局变量$n print "Hello, number $n!/n"; } &func;# Hello, number 3! &func;# Hello, number 4! &func;# Hello, number 5!

[3] 子程序的定义是全局的;除非你使用一些强有力的技巧,否则不存在所谓的私有子程序。
[4] 假如定义了两个重名的子程序,那么后面的那个子程序会覆盖掉前面的。(重名这种做法很不好!)


(2) 返回值
在Perl中,所有的子程序都有一个返回值——子程序并没有“有返回值”和“没有返回值”之分。但并不是所有的Perl子程序都包含有用的返回值。
注意:
在子程序中,最后一次运算的结果(不管是什么)——即,最后执行的表达式,而非程序代码的最后一行,都会被自动当成子程序的返回值。
例如:
&func;# Hello, number 1! &func;# Hello, number 2! sub func { $n+=1;# 全局变量$n print "Hello, number $n!/n"; } &func;# Hello, number 3! &func;# Hello, number 4! &func;# Hello, number 5! $ret=&func;# Hello, number 6! print "$ret/n";# 1,print成功输出,则返回1

 

(3) 参数
Perl子程序可以有参数(argument)。要传递参数列表(argument list)到子程序里,只要在子程序调用的后面加上被括号圈引的列表表达式(list expression)就行了。
Perl会自动将参数列表化名为特殊的数组变量@_,该变量在子程序执行期间有效。子程序可以访问这个数组,以判断参数的个数以及参数的值。
这表示,子程序的第一个参数存储于$_[0],第二个参数存储于$_[1],依次类推。但是,请特别注意,这些变量和$_变量毫无关联。
参数列表总得存进某个数组变量里,好让子程序使用,而Perl将这个数组叫做@_,仅此而已。

(4) 子程序中的私有变量
默认情况下,Perl中所有的变量都是全局变量。
我们可以用my操作符来随时创建一个私有的词法变量(lexical variables)。
例如:
sub max { my($m,$n);# 该语句块中的新私有变量 ($m,$n)=@_;# 将参数赋值给变量 if ($m>$n) {$m} else {$n} } $bigger=max(3,5); print "$bigger/n";# 5 if (defined($m)) {print "$m/n"} else {print "undefined/n"}# undefined

注意:
Perl允许省略语句块中最后一个分号,但实际上,通常只有在程序代码简单到整个语句块只有一行时,才有必要省略分号。

 

(5) 长度可变的参数列表
在真实的Perl代码中,常常把更长的(任意长度的)列表作为参数传递给子程序。
子程序可以很容易地通过检查@_数组的长度来确定参数的个数是否正确。
sub max { if (@_ != 2) { print "WARNING! &max should get exactly two arguments!/n" } my($m,$n);# 该语句块中的新私有变量 ($m,$n)=@_;# 将参数赋值给变量 if ($m>$n) {$m} else {$n} } $bigger=max(3,5,7); print "$bigger/n";# 5 if (defined($m)) {print "$m/n"} else {print "undefined/n"}# undefined

在追求实用的Perl程序中,这种检查方式很少见,比较好的做法是让子程序能够适应任意数目的参数。
【更好的&max子程序 —— “高水线”的算法】
sub max_variable_argument_list{ #$first=$_[0]; #shift(@_);# 删除第一个元素 # 上面两行代码简写为一行 $first=shift(@_); foreach (@_) {# 遍历比较剩余元素 if ($first < $_) { $first=$_ } } $first# 记得写返回值 } $bigger=max_variable_argument_list(3,5,7); print "$bigger/n";# 7 $bigger=max_variable_argument_list(12,4,2); print "$bigger/n";# 12 $bigger=max_variable_argument_list(-2,5,-3); print "$bigger/n";# 5

 

(6) 关于词法(my)变量
注意:
[1] 词法变量的作用域受限于(引入它的)最内层语句块(或文件)。
[2] my操作符并不会更改变量赋值时的上下文。
my($num)=@_;# 列表上下文,和($num)=@_;相同,$num会被设为第一个参数
my $num=@_;# 标量上下文,和$num=@_;相同,$num会被设为参数的个数
[3] 记住:在my不使用括号时,只用来声明单个词法变量。
my $a, $b; # 错,没声明$b
my($a, $b);# 两个都声明了

(7) use strict编译命令
Perl通常是个相当宽容的语言。但是,也许你会想要Perl更严格一些,这时可以使用use strict编译命令。
建议:比整个屏幕长的程序都应该加上use strict。

(8)  return操作符
return操作符会从子程序中立即返回某个值。
习惯:只有返回发生在子程序的最后一行代码之前的时候,才需要使用return,否则可以省略return。
例如:
my @name=qw/wcdj gerry yj/; my $result=&which_element_is("gerry",@name); print "$result/n";# 1 sub which_element_is { my($what,@array)=@_; foreach (0..$#array) {# 数组array中所有元素的下标 if ($what eq $array[$_]) { return $_;# 一发现就提前返回 } } -1;# 没找到符合条件的元素(return在这里可有可无) }

 

(9) 省略“&”与号
真正的省略规则:
除非你知道Perl所有的内置函数名,否则请务必在调用函数时使用“&”与号。

(10) 非标量返回值 —— 返回列表值
子程序不仅可以返回标量值,如果你在列表上下文中调用它,它就能返回列表值。

(11) 持久性私有变量 —— 作用类似C中的static关键字
在子程序中可以使用my操作符来创建私有变量,但每次调用这个子程序的时候,这个私有变量都会被重新定义。使用state操作符来声明变量,我们便可以在子程序的多次调用间保留变量的值,并将变量的作用域局限于子程序中。
例如:
use 5.010;# 5.10 running_sum(5,6); running_sum(1..3); running_sum(4); sub running_sum { state $sum=0; state @numbers; foreach my $number ( @_ ) { push @numbers,$number; $sum+=$number; } say "The sum of (@numbers) is $sum"; }

 

输出:
The sum of (5 6) is 11
The sum of (5 6 1 2 3) is 17
The sum of (5 6 1 2 3 4) is 21
注意:
在Perl 5.10中,我们不能在列表上下文中初始化数组和哈希这两种类型的state变量。也许在以后的版本中可以。

 

你可能感兴趣的:(Perl Learning (4) —— 子程序)