Perl匿名數組、hash和autovivification特性


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

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

構造匿名對象

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

@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()。

# 以下等價
@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賦值給一個引用變量:

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

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

解除匿名對象的引用

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

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時將會看到這種行為

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

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM