perl 引用 z

來源:互聯網
上載者:User

當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";
   13   }
%table是一個普通的雜湊,我們從它這裡可以取得一列鍵,對鍵進行排序,並遍曆所有的鍵。這裡唯一使用'引用'的是第10行。$table{$country} 查看了雜湊中的鍵$country並取得它的值。這個健值是對應國家中的城市數組的'引用'。 使用規則 1 告訴我們可以通過使用 @{$table{$country}}來恢複整個數組。第10行就象

        @cities = @array;
不同的是這裡的數組的名字被'引用' {$table{$country}}所替代。符號 @ 告訴Perl去擷取整個數組。得到了城市的列表後,我們照樣對其進行排序,合并城市名,並列印出來。

第2-7行負責建立資料結構,如下:

    2   while (<>;) {
    3    chomp;
    4     my ($city, $country) = split /, /;
    5     $table{$country} = [] unless exists $table{$country};
    6     push @{$table{$country}}, $city;
    7   }
第 2-4 行擷取城市和國家的名稱。第5行查看這個國家名稱是不是已經作為一個鍵存放在雜湊裡面了,如果沒有,程式就使用符號[] (建立規則 2)建立一個新的、空的匿名數組,同時把一個指向這個匿名數組的'引用'作為健值放到雜湊裡面去了。

第6行將城市名放到對應的數組裡面。$table{$country} 現在儲存了一個'引用',它指向所對應的國家的城市的數組。第6行就象

        push @array, $city;
不同的是這裡的數組名被{$table{$country}}所替代。 命令 push 將城市名加到這個'引用'指向數組的最後。

這裡有一個要點被我忽略了。第5行是不需要的。我們可以取掉它。

    2   while (<>;) {
    3    chomp;
    4     my ($city, $country) = split /, /;
    5   ####  $table{$country} = [] unless exists $table{$country};
    6     push @{$table{$country}}, $city;
    7   }
如果在雜湊 %table 中已經有這個國家名 $country的記錄,那麼,加不加第5行沒有任何區別。第6行會自己定位到$table{$country}這個'引用'指向的數組,把值 $city 放到數組中去。但是如果在%table中沒有那個鍵,比如Greece,那麼它會怎麼辦呢?

這是Perl,它會自己準確地完成工作。你想把一個Athens賦值給一個不存在地數組,那麼Perl會協助你建立一個新的、空的匿名數組,將它放到雜湊%table裡面去,然後把值 Athens 放到這個數組中。這個被稱為'自動產生' --讓事物自己自動產生出來。 Perl 發現在雜湊裡面沒有這個鍵,就自動地建立了一個新的雜湊記錄。 Perl 發現你想要使用數組作為雜湊的健值,它就自動建立一個匿名的空數組,並將指向這個數組的'引用'放到那個雜湊中去。一般, Perl 建立的數組只有一個成員大小,用於儲存這個新的城市名。

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

其他集錦
我承諾以10%的細節來使你得到90%的好處,那就意味著我跳過了90%的知識的細節。現在來看一下其中的重要的部分,這個比閱讀手冊 the perlref manpage 要容易得多,手冊討論了100%的細節。

手冊 the perlref manpage中的一些集錦:

你可以對任何東西建立'引用',包括標量,函數和其他的引用。 

在 使用規則 1 中,當大括弧裡面是一個象$aref這樣的標量變數時,你可以省略掉這個大括弧。例如, @$aref 和 @{$aref}是一樣的,$$aref[1] 和 ${$aref}[1]是一樣的。 如果你是初學者,建議你還是養成加上大括弧的習慣。 

下面的操作不會copy '引用'指向的數組: 
        $aref2 = $aref1;
你將得到兩個'引用',它們都指向同一個數組。如果你修改了$aref1->;[23]的值,那麼你查看變數$aref2->;[23]時,它也相應地變了。

要copy這個數組,你需要這樣

        $aref2 = [@{$aref1}];
使用符號 [...] 來建立一個新的匿名數組, 而且這個新的數組的'引用'被賦值給了$aref2 。 這個新的數組用'引用'$aref1所指向的數組的內容來初始化。

同樣的,要copy一個匿名雜湊,你需要這樣

        $href2 = {%{$href1}};

如果要判斷一個變數儲存的內容是不是'引用',使用函數ref 。如果它的參數是'引用',返回的值是'真'。實際上,它做得更好:如果是一個雜湊的引用,它返回'HASH',如果是一個數組的引用,那麼就返回'ARRAY'。 

如果你想像字串一樣使用'引用'的話,你得到的字串就像 
        ARRAY(0x80f5dec)   or    HASH(0x826afc0)
如果看到一個像這樣的字串,你應該知道你錯誤地輸出了一個'引用'。

這種顯示方式的另一個作用是你可以用eq來比較兩個'引用',看它們是不是指向相同的東西。(你通常可以使用 == 來比較,因為它更會)

你可以像使用'引用'一樣來使用一個字串。如果你使用"foo"作為一個數組的'引用',它就是指向數組 @foo的一個引用。這被稱為'軟引用'或‘符號引用 '。 使用申明 use strict 'refs' 可以取消這個功能,如果你不小心使用了它,會導致各種可能的錯誤。 

你可能更喜歡查看 the perllol manpage,而不是手冊 the perlref manpage;它詳細地討論了列表的列表和多緯數組。然後,你可以繼續學習手冊 the perldsc manpage;它是資料結構的Cookbook, 它提供了處理雜湊的數組,數組的雜湊,以及其他資料結構的方法。

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

摘要
每個人都需要複合的資料結構,在Perl中我們的辦法是通過'引用'來實現。這裡有四個重要的操作'引用'的規則:兩個用於建立'引用',另外兩個用於使用'引用'。 一旦掌握了這些規則,你可以用'引用'來處理很多重要的事情。 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.