子程序sub

1. 定义子程序

子程序由sub关键字定义花括号表示函数体范围。

子程序不需要事先声明。

如果定义了两个相同名字的子程序,后面的会覆盖前面的。

1
2
3
4
5
sub marine {  # marine是子程序名
print "this is a test\n";
}
&marine;#子程调用,&marine写在程序定义之前也可以运行。
# 也可以直接用marine调用,这样必须写在程序定义之后

2. 子程序调用 &

”&函数名(参数列表);“来调用子程序,如果不需要传入参数,就不加,”&函数名;“

&符号可以省略:

  1. 子程序在使用之前定义好了
  2. 调用子程序时,参数列表放在括号里。

&不可省略:子程序名字和perl默认函数名字相同时绝对不可以省略

3. 返回值

perl中所有的子程序都有返回值,所以perl默认以最后一次运算的结果作为返回值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
sub sum_of_fred_barney {  #函数求变量$fred,$barney的和
print ("sum is ",($fred+$barney),"\n");# 这里的$fred,$barney是全局变量
$fred+$barney; # 最后一个表达式的结果作为返回值
}
$fred = 1;
$barney = 1;
print &sum_of_fred_barney,"\n";
输出:
sum is 2
2
### 另一种情况
sub sum_of_fred_barney { #函数求变量$fred,$barney的和
print ("sum is ",($fred+$barney),"\n");# 这里的$fred,$barney是全局变量
#$fred+$barney; # 将这一行注释掉
}
$fred = 1;
$barney = 1;
print &sum_of_fred_barney,"\n";
输出:
sum is 2
1 # 最后一条语句是print函数,这里函数返回1,表示成功执行函数

最后一次运算结果,而不是最后一行表达式,如下面这个例子

1
2
3
4
5
6
7
8
9
10
11
12
$fred = 2;
$barney = 1;
sub sel {
if ($fred > $barney) {
$val = 1; # 这条语句是最后执行的。
}
else {
$val = 0;
}
}
&sel;
print '$val'," is $val\n";
return返回

如果子程序执行到一半需要返回,用return;

1
2
3
4
5
6
7
8
sub find4{ #从列表中找到大于4的第一个值,找到后立马返回这个值,找不到返回-1
foreach(@_) {
if ($_ > 4) {return $_;}
}
-1;
}
@f4 = qw/1 3 2 1/;
print &find4(@f4);

4. 参数

perl自动将参数化列表保存在数组**@_**中,在子程序定义的时候不需要写参数表。

1
2
3
4
5
6
7
sub max { # 返回两个数的最大值
if($_[0] > $_[1]) { $_[0] ;} #$_[0]是子程序调用时第一个参数,$_[1]是第二个参数。
else { $_[1] ;}
}
$fred = 2;
$barney = 1;
print "the max of ",'$fred'," and ",'$barney'," is ",&max($fred,$barney),"\n";

子程序调用的时候有多余的参数,会被忽略,反正程序中也用不到。

也可以根据 标量上下文中的列表这个概念来判断传入的参数个数对不对,如果多了就输出一段警告。

1
2
3
4
sub max {
if(@_ != 2)
print "WARNING!\n";
}

也可以传入任意长度的参数,只要是功能需要

1
2
3
4
5
6
7
8
9
10
11
sub max{  # 求一个列表中的最大值
$max_of_list = shift @_;
foreach (@_) {
if($max_of_list < $_) {
$max_of_list = $_;
}
}
$max_of_list;
}
@list = qw/1 2 3 4/;
print "the max of ",'$fred'," and ",'$barney'," is ",&max(@list),"\n";

5. 子程序中的私有变量 my

my操作符来定义子程序中的私有变量,作用域只是该子程序。

可以用来对子程序参数重命名,也就是将参数保存在这些私有变量里,因为默认的@_数组保存变量不好识别,变量多了不知道各个变量是什么意思。

1
2
3
4
5
sub max {
my($l,$r) = @_;
if($l > $r) { $l; }
else { $r; }
}

my操作符不加()的时候只能声明单个变量。

1
my $fred,$barney; # 只声明了$fred;

6. 子程序持久性私有变量 state

用state声明,子程序在多次调用的时候保留该变量的值,类似于C++中的static变量。

7. 自定义 排序规则子程序(sort-definition subroutine)

通过自己定义规则子程序对元素进行排序。可以是正序、反序、或者按照键值对哈希排序等。

比如:

1
2
3
4
sub sort_any {
if($a>$b) {return -1;} # 大的在前,降序
else {return 1; }
}

对于上面程序中的变量$a,$b是perl为我们定义好的,不需要自己定义,它们是来自排序列表中的两个元素。

子程序会返回一个数字,用来描述两个元素的比较结果。如果返回-1,表示$a应该在$b之前,返回1,$a应该在$b之后,返回0表示无所谓谁先谁后。上面程序中$a>$b时返回-1,表示将大的$a排在前面,也就是降序排列。

使用自定义排序规则

1
2
3
4
5
6
7
8
sub sort_any {
if($a>$b) {return -1;} # 大的在前,降序
else {return 1; }
}
@arr = qw/10 2 20 40/;
@arr_sort = sort sort_any @arr; ## 调用自定义排序函数
print "@arr_sort\n"; # output : 40 20 10 2
print "@arr\n"; # output : 10 2 20 40 不会改变原来列表

另外,可以用飞船操作符<=>,无分号结尾

1
2
sub sort_any { $a <=> $b } #表示升序排列
sub sort_any { $b <=> $a } #表示降序排列

按照哈希值排序

其实是按照值对键进行排序,比如按照分数对人名进行排序。

1
2
3
4
5
6
7
%h = ('dong',10,'wang',20,'liu',30);
sub sort_hash {
$h{$b}<=>$h{$a} #降序,根据值进行排序
}
@l = sort sort_hash keys %h; # 对键进行排序
foreach (@l) {print $_;print "\t";}
# output : liu wang dong

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!