由于公司需要,本人最近在学习Perl这种脚本语言,本文是我在学习Perl的过程中总结出来的一些心得和笔记,希望能够帮助也在学习Perl的各位同僚。废话不多说直接上干货!!!
———————————— 干货分割线 ——————————————————————————
Pe r l中,用户定义的函数称为子例程.子例程可以在任何位置被调用,包括在其他子例程中调用.
创建函数:
sub 函数名{
代码语句;
...
代码语句;
}
Exp:
sub yesno{
Print “R U sure?”;
$answer = <STDIN>;
}
调用子例程的两种方法:
1.$yesno(); #任何位置都可以使用该方法
2. yesno(); #代码中已经声明了子例程可以使用该方法.
Exp:
sub countdown{
for($i = 10; $i >=0; $i--){
print “$i -”;
}
}
Print “T-minus:”;
Countdown();
Print “Blastoff”;
子例程的返回值:子例程的返回值是它的内部计算的最后一个表达式的值或者是return语句显示返回的值.
Exp:
1.不用return关键字:
Sub two_by_four{
2*4; #此处与Java不同,可不写return关键字;
}
Print 8 * two_by_four(); #输出 64;
2.使用return关键字:
当程序需要在子例程结束前返回,或当想要知道返回的是什么值,而不是想要执行到最后表达式的值时,就需要使用r e t u r n语句。
Exp:
my $x = 70;
if(x_greaterthan100()){
Print “$x is greater than 100\n”;
}else{
print “子例程返回为0.所以在if中无输出\n”;
}
Sub x_greaterthan100{
Return(1) if($x > 100);
0;
}
PS:最好把子函数写在父函数后面,这样在传递参数时便不会提示警告.
子例程能够返回数组和哈希结构,也能返回标量.
Exp:
#!/usr/bin/perl
use strict;
use warnings;
my @a = shift_to_upper();
for(my $i = 0; $i <= $#a; $i++){
print "$a[$i]\n";
}
sub shift_to_upper{
my @words = qw(cia fbi un nato unicef);
foreach(@words){
$_ = uc($_); #小写转化为大写
}
return (@words);
}
子例程传递参数的写法:
Subname(arg1,arg2,arg3);
Subname arg1,arg2,arg3; #该子例程被定义后,才能使用该写法
$subname(arg1,arg2,arg3);
在写子函数时,有两种写法:
1. Sub subroutine($$){},该方法要求在调用该方法时必须传递两个参数;
2. sub subroutine(){},该方法对传参个数没有严格要求。
在子例程中,被传递的参数可以通过P e r l的特殊变量@ 来访问。下面这个代码段显示了为函数传递参数(3个字符串直接量)和输出参数的情况:
#!/usr/bin/perl
use strict;
use warnings;
sub printargs{
print join(',',@_); #参数通过@_传递过来(3个字符串直接量)
}
printargs('aaa','bbb','ccc ddd');
输出:aaa,bbb,ccc ddd
exp:
use strict;
use warnings;
sub display_box_score{
(my $hits,my $at_bats) = @_; # =@_; 为固定写法,只要注意传递的参数个数即可
print "这里的hits为:$hits\n";
print "这里的at_bats为:$at_bats\n";
}
display_box_score(50,210);
PS:
1.当参数为1个时,输出为:
因为at_bats没有参数,所以报错;
2.当参数个数>2时,不影响程序结果,只是后面的参数没有接收到而已
3.@ _包含了传递给子例程的原始参数的别名。如果修改了@ _(或者修改了@ 的任何元素),就会修改参数列表中的元素变量。
传递数组和Hash结构
1.一个参数时
@sorted_items = sort_numberically(@items);
Sub sort_numberically{
Print “sorting …”;
Return (sort{$a ó $b} @_);
}
PS:在该子例程中,@items通过@_进行引用
2.多个参数时
Exp:
Display_arrays(@first,@second);
Sub Display_arrays{
(@a,@b) = @_;
Print “The first array:@a\n”;
Print “The second array:@b\n”;
}
输出:The first array:[@_的全部值]
报错
The second array:[空值]
PS: @b并不会得到参数;
3.参数为标量和Hash时:
参数为混合体时,只要标量在参数列表中首先被传递,且知道有多少个标量。
Exp:
Sub lots_of_args{
($first,$second,%hash) = @_;
}
lots_of_args($foo,$bar,%myhash);
作用域:
Exp1:
$weight = 150;
Print moonweight;
Sub moonweight{
Return ($weight/6);
}
PS:
缺点:全局变量$weight传递给子函数,且必须确保正确设置$weight.
Exp2(升级版):
Print moonweight(150);
Sub moonweight{
($weight) = @_;
Return ($weight / 6);
}
PS:
优点:不必设置外部变量,将参数自然而然传递给子函数内部。
函数嵌套调用的例子:
#!/usr/bin/perl
#use strict;
#use warnings;
print "please enter data,separated by commas:\n";
my ($data,@dataset);
$data = <STDIN>; chomp $data; #从终端输入放入标量中
@dataset = split(/[\s,]+/,$data); #将标量按照某种格式分割,放入数组 /[\s,]+/:匹配多个空格或,
print "Median:",median(@dataset),"\n";
print "Mean:",mean(@dataset),"\n";
print "Standard Dev.:",std_dev(@dataset),"\n";
#求数组中元素的个数
sub mean{
my (@data) = @_; #从外部接受数据时定义的标量加()
my $sum;
foreach(@data){
$sum += @_;dsf
}
return ($sum / @data);
}
#返回数组中间的数,若为偶数,则返回两个数的平均值
sub median{
my (@data) = sort {$a <=> $b} @_; #将原数组重新排序
if(scalar (@data) % 2){
return ($data [@data / 2]); #@data/2的返回值向上取整
}else {
my ($upper ,$lower);
$upper = $data[@data / 2];
$lower = $data[@data / 2 -1];
return (($lower+$upper) / 2);
}
}
sub std_dev{
my (@data) = @_;
my ($sq_dev_sum,$avg) = (0,0);
$avg = mean(@data);
foreach my $elem(@data){
$sq_dev_sum += ($avg - $elem) ** 2;
}
return (sqrt($sq_dev_sum / @data - 1));
}
声明Local变量:
Exp:
Sub myfunc{
Local($foo) = 56;
}
用local声明的变量和用my几乎相同。差别是:声明为局部变量的那些变量,可以在它的作用域范围内的代码块中看到,也可以在从该代码块中调用的任何子例程中看到。基本都用my生命而不用local.