现在的位置: 首页 > 综合 > 正文

perl 引用(数组和hash引用)

2013年05月03日 ⁄ 综合 ⁄ 共 7056字 ⁄ 字号 评论关闭

转自:http://www.chinaunix.net/old_jh/25/504623.html

为推广perl尽一点力,特将perl引用的一篇文章翻译了一下,没有仔细查错,有问题请和我联系。本文可以从下面地址获得英文版本: 
http://search.cpan.org/~nwclark/perl-5.8.6/pod/perlreftut.pod 



 perlreftut - Mark 的一个简单的'引用'教程  


*名称   
*描述   
*谁需要复杂的数据结构?  
*解决办法  
*语法  
     >;创建应引用   
         创建规则 1  
       >;使用引用  
         使用规则1  
              使用规则2  
        >;一个例子  
     >;箭头符号规则  
解决方法   
其他集锦  
摘要   
感谢   
     >;发布要求  

-------------------------------------------------------------------------------- 


名称 
perlreftut - Mark的一个简单的'引用'教程  



-------------------------------------------------------------------------------- 


描述 
在perl5中,一个重要的功能是提供了处理复杂数据类型的能力,比如多纬数组和嵌套的哈希。为了实现这个,perl5引入了一个要素-'引用',并使用引用来处理perl中复杂的、结构化的数据。 不幸的是,这里有大量的有趣的语法需要学习,但手册却很难理解。手册描述的相当完整,但是有时候人们却发现一个问题,它不能告诉人们那些是重要的,那些是不重要的。 

幸运地是,你只需要了解手册上10%的知识得到90%的好处。本文就是告诉你其中的10%。 



-------------------------------------------------------------------------------- 

谁需要复杂的数据结构? 
始终伴随着Perl 4的一个问题是怎么样来描述一个值是列表的哈希表。Perl 4 有哈希但是它的值必须是标量,不能是列表。 

你为什么需要一个列表的哈希结构呢?让我们来看一个简单的例子:你有一个包含城市和国家名称的文件,如下: 

        Chicago, USA 
        Frankfurt, Germany 
        Berlin, Germany 
        Washington, USA 
        Helsinki, Finland 
        New York, USA 
你想按照下面的格式输出,每一个国家出现一次,然后是一个按照字母顺序的该国家内城市的列表,如下: 

        Finland: Helsinki. 
        Germany: Berlin, Frankfurt. 
        USA:  Chicago, New York, Washington. 

一个很自然的解决方法是将国家的名称设置为一个哈希结构的键,和国家名称对应的健值是这些国家内的城市的一个数组。 每一次,你读取一行输入,将其分成国家和城市两个数据。查看'国家名称'的键所对应的城市列表,然后把新的城市加入那个列表中。当你完成了整个输入,然后将整个哈希中每个健对应的健值-城市名的列表作一个排序,然后打印出来。 

如果哈希值不能是列表,你就无法完成工作了。在Perl 4中,哈希的值不能是列表。它们只能是字符串。所以你必须把所有的城市名合并成一个字符串。当需要输出时,你再把这个字符串分拆成一个列表,然后对列表排序,最后将列表中的数据转成字符串输出。这样做非常烦琐并容易出错。而且让人沮丧的是,Perl已经拥有的优秀的列表功能无法使用了。 



-------------------------------------------------------------------------------- 

解决方法 
当Perl进化到Perl 5时,我们必须考虑到哈希原来的设计:哈希的键值必须是标量。解决办法就是采用'引用'。 

一个'引用'就是一个指向一个完整列表或完整哈希(或指向其他的东西,比如函数)的标量值。名字就是你比较熟悉的一种'引用'。 考虑一下美国的总统:一包杂乱的血肉。但是当我们谈到它,或者需要在计算机程序中描述它,你需要的只是一个简单的标量'George Bush'。 

Perl中的'引用'就像列表和哈希的名字。它们是Perl中私有的,内部的名字,所以你可以确信它们是明确的,不像'George Bush', 一个'引用'只指向一个东西。你总是可以知道它指向什么。如果你有一个指向数组的'引用',你可以从它恢复出整个数组。如果你有一个指向哈希的'引用',你可以根据它恢复出整个哈希。但是这个'引用'仍旧是一个简单、紧凑的标量。 

你不能使用一个健值是数组的哈希;哈希的健值必须是标量。我们被这个束缚住了。但是一个简单的'引用'能指向一个完整的数组,'引用'是标量,所以你可以使用指向数组的'引用'组成的哈希,它就像一个数组的哈希一样,和数据的哈希一样有用。 

稍后我们会再回到这个‘城市-国家’的问题来。我们先来看一些操作'引用'的语法。  



-------------------------------------------------------------------------------- 


语法 
创建'引用'仅有两种方法,使用它也是两种。 


创建引用 

创建规则 1 
如果你在一个变量前加一个'\'号,你就得到了这个变量的'引用'。 

    $aref = \@array;         # $aref 保存着指向@array的'引用' 
    $href = \%hash;          # $href 保存着指向%hash的'引用' 
当你把'引用'保存在类似 $aref 或 $href的变量中,你就可以象操作其他标量一样copy或保存它。 

    $xy = $aref;             # $xy 现在保存了指向 @array 的'引用' 
    $p[3] = $href;           # $p[3] 现在保存了指向 %hash 的'引用' 
    $z = $p[3];              # $z 现在保存了指向 %hash 的'引用' 
这些例子展示了如何创建命名变量的'引用',但是有时候,我们创建的数组或哈希没有名字。这个和你使用没有放到变量中去的字符串'\n'或数字'80'类似。 

创建规则 2 

[ ITEMS ] 创建了一个新的、匿名的数组,并返回一个指向这个数组的'引用'。 { ITEMS } 创建了一个新的、匿名的哈希,并返回那个哈希的一个'引用'。 

    $aref = [ 1, "foo", undef, 13 ];   
    # $aref 保存了这个数组的'引用' 
    $href = { APR =>; 4, AUG =>; 8 };    
    # $href 保存了这个哈希的'引用' 
从规则 2 中得到的'引用'和从规则 1 中得到的'引用'是同一种类型的: 

        # 这里: 
        $aref = [ 1, 2, 3 ]; 
        # 和上面一样: 
        @array = (1, 2, 3); 
        $aref = \@array; 
前面一种方法是后面两行的缩写,除了第一种方法没有创建一个多余的数组变量@array。 

如果你只是编写符号 [], 你将得到一个新的、空匿名数组。如果你使用符号 {},就能得到一个新的、空匿名哈希。 


使用引用 
当你创建了一个'引用'后,你可以对它做什么操作呢?它是标量,你可以象处理任何标量一样保存和取回它。除此之外,还有两种使用方法: 


使用规则 1 
你可以始终用一个带有大括号的数组'引用',来替换一个数组的名字。例如,用 @{$aref} 代替 @array。 

下面是一个用法的一些例子: 

数组: 

        @a              @{$aref}                一个数组 
        reverse @a      reverse @{$aref}        对一个数组做倒序排序 
        $a[3]           ${$aref}[3]             数组中的一个成员 
        $a[3] = 17;     ${$aref}[3] = 17        对一个成员赋值 
上面每行中,两个表达式实现的是同一种功能。左边那个是对数组@a操作,右边那个是对'引用'$aref所指向的数组操作。它们对数组产生相同的作用。 

使用哈希的'引用'和数组的'引用'完全一样。 

        %h              %{$href}              一个哈希 
        keys %h         keys %{$href}         从哈希中将键取出来 
        $h{'red'}       ${$href}{'red'}       哈希中的一个成员 
        $h{'red'} = 17  ${$href}{'red'} = 17  对一个成员赋值 
你对一个'引用'无论想做什么,使用规则 1 已经告诉你怎么做了。 你只要象使用常规的数组或哈希一样编写Perl代码,然后把数组或哈希的名字用 {$reference}来替代。‘当我只有一个'引用'时,怎么来遍历整个数组?’你这样写: 

        for my $element (@array) { 
           ... 
        } 
接着用'引用'替代数组名@array: 

        for my $element (@{$aref}) { 
           ... 
        } 
‘怎当我只有一个'引用'时,怎么来打印一个哈希的内容?’先写一个打印整个哈希的代码: 

        for my $key (keys %hash) { 
          print "$key =>; $hash{$key}\n"; 
        } 
然后用'引用'代替那个哈希的名字: 

        for my $key (keys %{$href}) { 
          print "$key =>; ${$href}{$key}\n"; 
        } 

使用规则 2 
使用规则 1 是你真正需要的,因为它告诉了你怎么来处理一个'引用',而它对几乎任何的'引用'都有效。但是我们通常做的事情只是和数组或哈希中的一个成员有关,使用规则 1 却是很笨重的方法,所以还有简单的方法。 

${$aref}[3] 太难阅读,所以我们这样写 $aref->;[3]。 

${$href}{red} 写的太笨重, 所以我们这样写 $href->;{red}。 

如果 $aref 保存的是一个数组的'引用',那么 $aref->;[3] 就是这个数组的第四个成员。不要和 $aref[3] 相混淆,这个代表的是一个完全不同的数组的第四个成员,这个迷惑的数组是@aref。 变量 $aref 和 @aref 是完全不相关的,就像 $item 和 @item 一样。 

同样的, $href->;{'red'} 是哈希'引用' 的变量$href的一部分,甚至这是一个没有名字的哈希。而$href{'red'} 是另一个容易混淆的命名哈希 %href 的一部分。很容易忘记写上符号' ->;',如果出现这种情况,当你的程序从一个你不想取数据的数组和哈希中取出了成员,你会得到奇怪的计算结果。 


例子 
让我们来看一个例子: 

首先,记住 [1, 2, 3] 创建了一个匿名数组,包含了 (1, 2, 3),然后返回一个数组的'引用'。 

现在想一下: 

        @a = ( [1, 2, 3], 
               [4, 5, 6], 
               [7, 8, 9] 
             ); 
@a 是一个拥有三个成员的数组,每一个成员是另一个数组的'引用'。 

$a[1] 是其中的一个'引用'。它指向一个数组,这个数组包含了(4, 5, 6),因为这是一个数组的'引用',使用规则 2 告诉我们可以这样写 $a[1]->;[2],用来取得这个数组的第三个成员。  $a[1]->;[2] 值是6。 同样的,$a[0]->;[1] 值是 2。这里我们就像在使用一个二维数组;你可以是用 $a[ROW]->;[COLUMN] 来取得或设置数组中任何一行任何一列中的成员。 

这些符号看起来还是有些麻烦,所以还有更加简单的用法: 


箭头符号规则 
在两个下标之间的箭头是可选的。 

我们可以用这个写法$a[1][2]来代替$a[1]->;[2];它们是相同的。相对于$a[0]->;[1] = 23,我们这样写$a[0][1] = 23;它们也是相同的。 

现在它们看起来真的象二维数组了! 

你可以发现为什么箭头这么重要。没有它们,我们必须这样写${$a[1]}[2],而不是$a[1][2]。对于三维数组,它们使我们可以简单地写成$x[2][3][5]而不是写成难读的${${$x[2]}[3]}[5]方式。 



-------------------------------------------------------------------------------- 

解决办法 
下面是前面提出来的问题的解决方法,就是关于城市和国家名称的重新格式化。 

    1   my %table; 
    2   while (<>;) { 
    3    chomp; 
    4     my ($city, $country) = split /, /; 
    5     $table{$country} = [] unless exists $table{$country}; 
    6     push @{$table{$country}}, $city; 
    7   } 
    8   foreach $country (sort keys %table) { 
    9     print "$country: "; 
   10     my @cities = @{$table{$country}}; 
   11     print join ', ', sort @cities; 
   12     print ".\n"; 
   13   } 
这个程序分成两部分: 第 2--7 行完成数据的输入和数据结构的创建。 第 8-13 行分析这个数据并打印报告。我们设置了一个哈希 %table,它的键是国家名称,它的健值是这个国家名称对应的城市名的数组的'引用'。这个数据结构看起来如下: 

           %table 
        +-------+---+    
        |       |   |   +-----------+--------+ 
        |Germany| *---->;| Frankfurt | Berlin | 
        |       |   |   +-----------+--------+ 
        +-------+---+ 
        |       |   |   +----------+ 
        |Finland| *---->;| Helsinki | 
        |       |   |   +----------+ 
        +-------+---+ 
        |       |   |   +---------+------------+----------+ 
        |  USA  | *---->;| Chicago | Washington | New York | 
        |       |   |   +---------+------------+----------+ 
        +-------+---+ 
我们先来分析输出部分。假设我们已经拥有了这个结构,那么我们怎么来输出呢? 

    8   foreach $country (sort keys %table) { 
    9     print "$country: "; 
   10     my @cities = @{$table{$country}}; 
   11     print join ', ', sort @cities; 
   12     print ".\n"; 

抱歉!评论已关闭.