由于公司需要,本人最近在学习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个时,输出为:

 

r语言debug_函数

因为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.