Perl匿名數組、hash和autovivification特性

可有構建匿名的對象,這樣就不必去爲只用一兩次的數組、hash去取名字,有時候取名是很煩的事。數組

  • 使用中括號[]構建匿名數組
  • 使用大括號{}構建匿名hash
  • 不包含任何元素的[]{}分別是匿名空數組、匿名空hash

構造匿名對象

例如,在數組、hash中構建匿名數組:ui

@name=('fairy',['longshuai','wugui','xiaofang']);

%hash=('longshuai' => ['male',18,'jiangxi'],
        'wugui'     => ['male',20,'zhejiang'],
        'xiaofang'  => ['female',19,'fujian'],
       );

say "$name[1]";          # 輸出ARRAY(0x...)
say "$hash{wugui}";      # 輸出ARRAY(0x...)

say "$name[1][2]";
say "$hash{wugui}[1]";

若是不想在匿名數組中輸入引號,可使用qw()。scala

# 如下等價
@name=('fairy',['longshuai','wugui','xiaofang']);
@name=('fairy',[qw(longshuai wugui xiaofang)]);

在數組、hash中構建匿名hash:翻譯

@name=(         # 匿名hash做爲數組的元素
       {    # 第一個匿名hash
        'name'=>'longshuai',
        'age'=>18,
        'prov'=>'jiangxi',
       },
       {    # 第二個匿名hash
        'name'=>'wugui',
        'age'=>20,
        'prov'=>'zhejiang',
       },
       {    # 第三個匿名hash
        'name'=>'xiaofang',
        'age'=>19,
        'prov'=>'fujian',
       },
      );

%hash=(          # 匿名hash做爲hash的value
        'longshuai'=>{   # 第一個匿名hash
                      'gender'=>'male',
                      'age'   =>18,
                      'prov'  =>'jiangxi',
                     },
        'wugui'=>{    # 第二個匿名hash
                  'gender'=>'male',
                  'age'   =>20,
                  'prov'  =>'zhejiang',
                 },
        'xiaofang'=>{    # 第三個匿名hash
                     'gender'=>'female',
                     'age'   =>19,
                     'prov'  =>'fujian',
                    },
      );

say "$name[2]";       # 輸出HASH(0x...)
say "$hash[wugui]";   # 輸出HASH(0x...)

say "$name[2]{age}";
say "$hash{wugui}{prov}";

再例如,將一個匿名hash賦值給一個引用變量:unix

$ref_myhash = {
               name => 'Gilligan',
               hat => 'White',
               shirt => 'Red',
               position => 'First Mate',
              };

爲了後期維護方便,匿名數組、匿名hash中最後一個元素都使用了逗號。這個逗號並不會影響結果,可是卻給將來修改匿名對象帶來很大方便。code

解除匿名對象的引用

從上面實驗的結果中能夠看到,當輸出匿名對象時,其實輸出的是個引用。對象

say "$name[1]";       # 輸出ARRAY(0x...)
say "$hash{wugui}";   # 輸出ARRAY(0x...)

say "$name[2]";       # 輸出HASH(0x...)
say "$hash[wugui]";   # 輸出HASH(0x...)

既然是引用,就能夠解除引用,還原到數據對象:遞歸

  • 正常狀況下,使用@{數組引用}的方式解除數組引用,使用%{hash引用}的方式解除hash引用
  • 因此使用@{匿名數組}解除匿名數組,使用%{匿名hash}解除匿名hash
  • 注意,解除正常的數組、hash引用時,可使用非規範的解除方式(去掉大括號,如@$ref_name),可是解除匿名對象的引用,必須不能去掉大括號
  • 訪問匿名對象中的元素和正常對象同樣。通常沒有必要去獲取匿名對象中的元素,可是卻有必要設置匿名對象中的元素時,後面介紹autovivification時將會看到這種行爲

例如,解除匿名數組對象,並獲取匿名數組中的元素:ip

say "@{ ['longshuai','xiaofang','wugui'] }";   # 解除匿名對象的引用
say "@{ [qw(longshuai xiaofang wugui)] }";     # 解除匿名對象的引用
say "@{ [qw(longshuai xiaofang wugui)] }[1]";  # 獲取匿名對象中的第二個元素

解除匿名hash對象,並獲取匿名hash中的元素:字符串

$ref_hash={   # 構造匿名hash,賦值給引用變量
           'longshuai'=> ['male',18,'jiangxi'],
           'wugui'    => ['male',20,'zhejiang'],
           'xiaofang' => ['female',19,'fujian'],      
          };

@mykeys=keys %{ $ref_hash };  # 經過引用還原到匿名hash
say "@mykeys";                # 輸出匿名hash中的鍵
say $ref_hash->{wugui}[2];    # 輸出匿名hash中匿名數組的某個元素

再例如,直接在須要hash的地方構建一個匿名hash,並解除引用。

@mykeys=keys %{   # 解除匿名hash
                 { # 構造匿名hash
                  'longshuai'=> ['male',18,'jiangxi'],
                  'wugui'    => ['male',20,'zhejiang'],
                  'xiaofang' => ['female',19,'fujian'],
                 }
               };

say %{   # 解除匿名hash
       { # 構造匿名hash
        'longshuai'=> ['male',18,'jiangxi'],
        'wugui'    => ['male',20,'zhejiang'],
        'xiaofang' => ['female',19,'fujian'],      
       },
     };

如何區分匿名hash和一次性代碼塊

匿名hash使用大括號進行構建。但除了匿名hash,大括號還能夠用來包圍一堆語句,做爲只執行一次的語句塊。例如:

{
    my $name="longshuai";
    my $prov="jiangxi";
}
# 出了語句塊,上面兩個my標記的變量就失效了

那麼如何讓perl知道大括號是用來構造匿名hash的,仍是用來作一次性語句塊的?大多數時候,Perl根據上下文的環境會自動判斷出來,可是有些時候沒法判斷,這時能夠顯式告訴Perl,這是匿名hash的構造符號,仍是一次性語句塊的符號。

  • 大括號前面加上+符號,即+{...},表示這個大括號是用來構造匿名hash的
  • 大括號內部第一個語句前,多使用一個;,即{;...},表示這個大括號是一次性語句塊

+還能夠加在匿名數組的中括號前,以及hash引用變量、數組引用變量前,而不單單是匿名hash的大括號前,如+$ref_hash+[]+$ref_arr

@{ +[qw(longshuai wugui)]}   # 匿名數組中括號前
@{ +$ref_arr }           # 數組引用變量前
%{ +$ref_hash }          # hash引用變量前

Perl的autovivification特性

這個單詞,真的無語了,居然找不到對應的翻譯,是perl自造的詞,但卻應用到了多種語言中:Wiki Autovivification

根據它的功能,我將其大概解釋下:當解除引用時,若是解除目標不存在,perl會自動建立一個空目標,並且自動建立時,會自動遞歸補齊上層。注意,是解除引用時。

這就像unix下的mkdir命令的-p選項同樣,當建立某個目錄的時候,若是它的父目錄不存在,就會自動建立。

例如,下面的示例:

#!/usr/bin/perl
use 5.010;

push @{ $config{path} },'/usr/bin/perl';

say keys %config;        # 輸出:path
say $config{path};       # 輸出:ARRAY(0x...)
say $config{path}[0];    # 輸出:/usr/bin/perl

執行到push的時候,perl首先會發現@{}在解除一個引用,這個引用是$config{path},是一個hash引用,可是perl發現這個hash不存在,hash裏的key(即path)也不存在,並且既然是push操做,說明這個key對應的value是個列表。因而perl的autovivification特性,首先會構建一個空的hash對象%config={},而後建立hash裏的一個key:path,其值爲空列表,即$config{path}=[],最後將"/usr/bin/perl"這個字符串push到對應的列表中,即$config{path}=['/usr/bin/perl']

在上面的示例中,perl在解除引用時,自建了幾個層次:1.自建一個hash對象;2.自建hash對象中的一個元素;3.自建hash對象中某個元素的value部分。

必須注意,perl的autovivification功能只在解除引用的時候才自建,從解除引用的操做動機上看,當要解除引用,說明可能要操做引用對象中的數據了,那麼缺乏的部分應該要補齊。

若是不是在解除引用,那麼perl將根據語法特性決定是否自建對象。例以下面將自建數組@name和hash對象%person以及它的一個元素$person{name}。但這不是autovivification的特性,而是perl的語法特性。

push @name,"longshuai";
$person{name}="longshuai"

say "$name[0]";
say keys %person;

緊跟着上面的示例:

@{ $config{path} }[2]='/usr/bin/perl';

say $config{path};       # 輸出:ARRAY(0x5571664403c0)
say $config{path}[0];    # 輸出:空
say $config{path}[1];    # 輸出:空
say $config{path}[2];    # 輸出:/usr/bin/perl
say scalar @{$config{path}};   # 輸出元素個數:3
相關文章
相關標籤/搜索