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
Linux系列文章:https://www.cnblogs.com/f-ck-need-u/p/7048359.html
Shell系列文章:https://www.cnblogs.com/f-ck-need-u/p/7048359.html
网站架构系列文章:http://www.cnblogs.com/f-ck-need-u/p/7576137.html
MySQL/MariaDB系列文章:https://www.cnblogs.com/f-ck-need-u/p/7586194.html
Perl系列:https://www.cnblogs.com/f-ck-need-u/p/9512185.html
Go系列:https://www.cnblogs.com/f-ck-need-u/p/9832538.html
Python系列:https://www.cnblogs.com/f-ck-need-u/p/9832640.html
Ruby系列:https://www.cnblogs.com/f-ck-need-u/p/10805545.html
操作系统系列:https://www.cnblogs.com/f-ck-need-u/p/10481466.html
精通awk系列:https://www.cnblogs.com/f-ck-need-u/p/12688355.html