Perl解除引用:從引用還原到數據對象

使用引用能夠指向數據對象,這彷佛很簡單。數組

@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的引用同解除數組引用的方式同樣,使用引用符號%+引用的名稱便可。

例如,建立一個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中的元素(1)

對於普通的數組和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'}";

解除引用:取數組、hash中的元素(2)

除了上面的介紹的取元素方法,對於引用變量,還支持更簡潔的"瘦箭頭"指向法:只需使用引用變量名->元素索引便可。注意,箭頭兩邊必須不能有空格。

$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]獲取到的多是以一個引用,因此將其看成引用變量名便可。

相關文章
相關標籤/搜索