Perl学习笔记 引用和匿名(数组/散列/子例程)

引用

Perl的标量变量保存单个值;数组保存一个有序的标量变量;散列保存一个无序的标量集合作为值

个人觉得,正是因为有引用,将标量、数组和散列很好的结合在一起,才在处理复杂的数据结构中游刃有余,引用可以分别数组引用和散列引用,还有个是子例程引用

  1. 数组引用

    数组引用可以将数组和标量联系在一起

    $result = \@array;
    

    从标量再变回数组则叫做解引用

    @array_2 = @{$result};
    

    如果想访问@array数组的第一个元素,下述三种方式是等价的,个人喜欢第三种(其实是书中对引用如何可以进行省略的缩写,但是个人觉得还是按照正常写法更加能让别人看懂,不然代码可能会让大部分人都会搞晕了)

    $a = $array[0];
    $a = ${$result}[0];
    $a = $result -> [0];
    
  2. 散列引用

    其实对散列引用,也可以粗略理解为将散列转化为标量,那么散列和标量以及数组的又联系到了一起,用法跟数组引用一样,也是用反斜杠进行引用,然后用大括号进行解引用,最后在访问散列中的某个键对应的值

    $result = \%hash;
    %hash_2 = %{$result};
    $a = ${$result}{"one"};
    $a = ${$result} -> {"one"};
    

    其实将散列引用解引用后,就是一个正常的散列了,可以随意的使用(同样的,这里的大括号也是可以省略的,但是我一般都不省略,以防万一以后理解错了。。)

    @key = keys %{$result};
    

    将散列引用存入数组中,这样有效地将散列和数组结合在一起使用,然后在后续有需要的时候解引用后即可返回为散列

    @array = (\%hash, \%tmp);
    %hash_2 = %{$array[0]};
    
  3. 子例程引用

    理解了上述2个引用,那么子例程也是相同的用法

    sub sum {
        my @array = @_;
        my $sum = 0;
        map{
            $sum += $_;
        }@array;
        return($sum);
    }
    my $function = \∑
    

    引用后肯定也要解引用,子例程的解引用则是用小括号,比如用上述子例程对@array数组求和,同样也是用箭头使代码美观

    $array_sum = &$function(@array);
    $array_sum = $function -> (@array); 
    

匿名

引用是Perl处理复杂数据结构的有力工具的话,那么个人认为匿名则是将其功能进一步升华了。

  1. 先简单的介绍下怎么算是匿名数组,如果正常的引用过程是如下:

    @tmp = ("a", "bb", "ccc");
    $result = \@tmp;
    

    那么按照匿名数组的写法则是如下,可以有效的减少动用脑细胞去思考该如何命名上面的那个@tmp数组

    $result = ["a", "bb", "ccc"];
    

    会了匿名数组的写法,那么下述的数组中含有数组就很好理解了

    @array = (["a", "bb", "ccc"], "dddd");
    @array = (["a", "bb", "ccc"], ["d", "ee", "fff"]);
    

    那么应该就很好理解什么是二维数组了,所谓二维数组,就是上述的代码,数组有匿名数组;对数组里的第一个元素解引用,然后再读取解引用后的数组的第一个元素赋值于新的标量,可用箭头增加代码的可读性

    $result = $array[0] -> [0];
    
  2. 了解了匿名数组,那么匿名散列也是相同的意思,不同于匿名数组是用中括号,匿名散列则是用大括号表示

    @array = (
        {
            a => "aa",
            b => "bb",
        },
        {
            c => "cc",
            d => "dd",
        },
    )
    

    那么二维散列可以理解为散列里面有匿名散列

    %hash = {
        x =>{
                a => "aa",
                b => "bb",
            },
        c => "cc",
    }
    
    $result = $hash{x} -> {a}
    
  3. 匿名子例程也是跟匿名数组和匿名散列的理解一样,为了减少临时的命名,比如对上述的求和子例程,就可以写成下面这种简单的形式:

    $function = sub {
        my @array = @_;
        my $sum = 0;
        map{
            $sum += $_;
        }@array;
        return($sum);
    }
    
    $array_sum = $function -> (@array);
    

    如果将匿名子例程放入一个子例程中,比如将匿名子例程放入一个find子例程中:

    find(
        sub {
            my $a = "aaa";
            print $a."\n";
        },
        $path,
    )       
    

其实个人觉得匿名数组和匿名散列最大的作用在于Perl会自动创建空的匿名数组/散列的引用,比如下面的代码就非常实用

push @{$hash{$i}}, "aaa";

上面这个代码的理解是:在运行这个代码之前,$hash{$i}并不存在,但是在运行代码时,我们设置了一个数组引用@{$hash{$i}},那么Perl就会自动创建一个匿名数组,只是在push之前,这个匿名数组是空的。

然后可以引申出在标量前面加个@就能转化为数组

@{$tmp} = (1,2,3);

并也可以对二维数组进行直接赋值,尽管这个二维数组之前还并不存在,这样导致了我们认为创建了一个新的有2个元素的数组,并在这个数组的第二个元素上写入了一个匿名数组,然后将”a”赋值于这个匿名数组的第3个元素。

$tmp[1] -> [2] = "a";

出了数组可以像上述这样操作,散列也是可以的,以二维散列的形式对其赋值

$hash{$a} -> {$b} = "c";

然后我们就可以用foreach循环提取出所有的键以及对应的值

foreach my $key1 (keys %hash){
    foreach my $key2 (keys %{$hash{$key1}}){
        $result = $hash{$key1} -> {$key2}
    }
}

至于子例程的引用和匿名子例程的使用,能够帮我们很好的理解面向对象的使用,有些Perl的模块的使用,就是在调用其子例程的引用

本文出自于http://www.bioinfo-scrounger.com转载请注明出处