可有構建匿名的對象,這樣就沒必要去為只用一兩次的數組、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