0%

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

引用

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

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

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

    $result = \@array;

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

    @array_2 = @{$result};

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

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

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

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

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

     @key = keys %{$result};

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

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

    理解了上述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转载请注明出处