使用引用能够指向数据对象,这彷佛很简单。数组
@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]
获取到的多是以一个引用,因此将其看成引用变量名便可。