使用引用能夠指向數據對象,這彷佛很簡單。數組
@name1=qw(longshuai wugui); @name2=qw(xiaofang tuner); $ref_name=\@name1; push @name2,$ref_name; print "@name2"; # 輸出:xiaofang tuner ARRAY(0xNAME1)
但若是想經過引用的方式取出數據對象的值呢,就像上面的print語句中,想要輸出@name2
中包含的@name1
的元素,而不是它的地址空間。這須要解除引用(dereference),將$ref_name
引用還原爲數據對象qw(longshuai wugui)
。數據結構
前方預警:dereference雖然不難,但初學之時,比較燒腦,比較眼暈。ui
在解釋引用解除以前,有必要先解釋下引用符號和數據對象的名稱。url
建立一個@name=qw(value1 value2 value3)
的數組,這個數組初始化時,數組名爲name,它是這個列表數據對象的第一個引用(注意,數組名是引用),引用方式爲@
符號+數組名name
,即@name
。實際上,真正規範的引用方式爲@{name}
。code
所以,當使用引用變量的方式引用數據對象時,只需把數組名稱換成引用變量的名稱便可(它們是等價的,都是對數據對象的引用),再加上@
符號便可,由於數組名稱和引用變量的名稱都是指向數據對象的名稱。對象
例如,將@name
的引用賦值給一個引用變量$ref_name
後(即$ref_name=\@name
),就可使用@$ref_name
的方式來表示解除引用,它和@name
是等價的關係。blog
如下幾種引用方式絕大多數時候是等價的,能夠用來作參考、對應。其實很好理解,只要把本來的對象名稱,替換成引用變量的名稱便可。索引
@{name} --> @{$ref_name} @{ name } --> @{ $ref_name } @name --> @$ref_name
若是引用變量的名稱有特殊符號,例如以$
符號做爲變量名的開頭符號,則不能省略大括號。固然,這種狀況基本不會出現,由於不符合命名規範,沒人會自找麻煩。ip
例如:get
#!/usr/bin/perl use 5.010; @name=qw(longshuai wugui); $ref_name=\@name; say "@{$ref_name}"; say "@{ $ref_name }"; say "@$ref_name";
同理,解除hash的引用同解除數組引用的方式同樣,使用引用符號%
+引用的名稱便可。
例如,建立一個hash:%myhash
,其中myhash是hash數據對象的名稱,%
是hash的引用符號。建立一個hash的引用變量$ref_myhash=\%myhash
,那麼引用變量對應的是hash的名稱myhash,因此經過引用變量名來解除hash引用時:%$ref_myhash
便可。
如下是幾種等價的引用方式:
%{name} --> %{$ref_name} %{ name } --> %{ $ref_name } %name --> %$ref_name
例如:
#!/usr/bin/perl use 5.010; %myhash=( longshuai => "18012345678", xiaofang => "17012345678", wugui => "16012345678", tuner => "15012345678" ); $ref_myhash =\%myhash; say %$ref_myhash;
對於普通的數組和hash,取得它們數據對象中的元素方式爲:
$arr_name[1] # 取得數組中的第二個元素 ${arr_name}[1] # 取得數組中的第二個元素 $hash_name{'mykey'} # 取得hash中key爲'mykey'的value ${hash_name}{'mykey'} # 取得hash中key爲'mykey'的value
那麼使用引用的方式來獲取數組、hash中的元素時,方式是同樣的,只需將引用變量替換爲對應的數據對象名稱便可。
例如:
# 數組元素的引用 ${name}[1] -> ${$ref_name}[1] ${ name }[1] -> ${ $ref_name }[1] $name[1] -> $$ref_name[1] # hash元素的引用 ${myhash}{'wugui'} -> ${$ref_myhash}{'wugui'} ${ myhash }{'wugui'} -> $ {$ref_myhash }{'wugui'} $myhash{'wugui'} -> $$ref_myhash{'wugui'}
例如:
#!/usr/bin/perl use 5.010; # 取數組的元素 @name=qw(longshuai wugui); $ref_name=\@name; say "${$ref_name}[1]"; say "${ $ref_name }[1]"; say "$$ref_name[1]"; # 取hash的元素 %myhash=( longshuai => "18012345678", xiaofang => "17012345678", wugui => "16012345678", tuner => "15012345678" ); $ref_myhash =\%myhash; say "${$ref_myhash}{'wugui'}"; say "${ $ref_myhash }{'wugui'}"; say "$$ref_myhash{'wugui'}";
除了上面的介紹的取元素方法,對於引用變量,還支持更簡潔的"瘦箭頭"指向法:只需使用引用變量名->元素索引
便可。注意,箭頭兩邊必須不能有空格。
$ref_name->[1] $ref_myhash->{'mykey'}
如此一來,取元素的寫法變得簡潔易讀,且能夠規範化,也不會再出現一大堆容易讓人疑惑的符號。固然,到目前爲止都只是簡單的引用方式,稍後介紹如何取複雜數據結構的元素時,將會看到不用箭頭的方式取數據將很是傷眼睛。
關於瘦箭頭取元素的用法,給個簡單的示例:
#!/usr/bin/perl use 5.010; @name=qw(longshuai wugui); $ref_name=\@name; say "$ref_name->[0]"; %myhash=( longshuai => "18012345678", xiaofang => "17012345678", wugui => "16012345678", tuner => "15012345678" ); $ref_myhash =\%myhash; say "$ref_myhash->{'wugui'}";
對於複雜數據結構,想要取它的元素並不是那麼容易。例如,hash的value中有數組做爲元素,該數組元素中又有數組的時候。
以CPAN::Config
的一部份內容爲例:
#!/usr/bin/perl use 5.010; %Config = ( 'auto_commit' => '0', 'build_dir' => '/home/fairy/.cpan/build', 'bzip2' => '/bin/bzip2', 'urllist' => [ 'http://cpan.metacpan.org/', \@my_urllist # 將數組my_urllist做爲元素 ], 'wget' => '/usr/bin/wget', ); $ref_Config=\%Config; @my_urllist=('http://mirrors.aliyun.com/CPAN/', 'https://mirrors.tuna.tsinghua.edu.cn/CPAN/', 'https://mirrors.163.com/cpan/', \@more_urllist # 將數組more_urllist引用做爲元素 ); @more_urllist=qw(http://mirrors.shu.edu.cn/CPAN/ http://mirror.lzu.edu.cn/CPAN/ );
如下是使用原始取得more_urllist數組中第2個元素的方式:
say "${$ref_Config}{'urllist'}"; # 取得key=urllist對應的value:數組 say "${$ref_Config}{'urllist'}[1]"; # 取得urllist數組中第二個元素:\@my_urllist引用 say "${$ref_Config}{'urllist'}[1][3]"; # 取得my_urllist數組中第4個元素:\@more_urllist引用 say "${$ref_Config}{'urllist'}[1][3][1]"; # 取得more_urllist數組中第2個元素
其實上面的寫法不是徹底規範寫法,由於每次取得引用後,都沒有對應於進行${$REF}的規範化。如下是與上面徹底對應的規範寫法:
say "${$ref_Config}{'urllist'}"; say "${$ref_Config}{'urllist'}[1]"; # 取得引用 say "${${$ref_Config}{'urllist'}[1]}[3]"; # 再次取得引用 say "${${${$ref_Config}{'urllist'}[1]}[3]}[1]"; # 最終取得元素
啊,個人眼睛,受不了,受不了。
若是使用瘦箭頭引用方式,則更簡潔易讀:
say "$ref_Config->{'urllist'}"; say "$ref_Config->{'urllist'}->[1]"; say "$ref_Config->{'urllist'}->[1]->[3]"; say "$ref_Config->{'urllist'}->[1]->[3]->[1]";
各元素之間的瘦箭頭能夠省略(引用變量名稱和元素之間的箭頭必須不能省略)。
say "$ref_Config->{'urllist'}"; say "$ref_Config->{'urllist'}[1]"; say "$ref_Config->{'urllist'}[1][3]"; say "$ref_Config->{'urllist'}[1][3][1]";
最後須要特別說明的是,當將複雜數據結構的引用看成子程序的參數傳給@_
時,甚至是@_
的一部分時,要特別當心地寫,一個不當心就錯了。
例如,子程序傳遞的參數形式以下:
mysub('aaa',\%Config)
那麼要在子程序內部取得more_urllist中的第二個元素,子程序中取元素相關的代碼大體以下:
my $first_arg = shift @_; say "${$_[0]}{'urllist'}"; # 等價於:$_[0]->{'urllist'} say "${$_[0]}{'urllist'}[1][3][1]"; # 等價於:$_[0]->{'urllist'}[1][3][1]
只需搞明白,@_
中的元素使用$_[N]
獲取,而$_[N]
獲取到的多是以一個引用,因此將其看成引用變量名便可。