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
Perl匿名数组、hash和autovivification特性的更多相关文章
- Perl 引用与匿名数组
写这篇是因为工作遇到一个需要使用列表作为hash的值的问题,这在Python中是非常简单而轻松的事,如下面这段python程序. def add_to_index(index, keyword, ur ...
- Perl Learning 5 Hash
[本文原创,未经同意请勿转载] 哈希是一种数据结构,它和数组的相似之处在于能够容纳随意多的值并能按需取用,而它和数组的不同在于索引方式,数组是以数字来索引.哈希则以名字来索引.也就是说.哈希的索引值, ...
- Java SE学习之数组——匿名数组和不规则数组
本文是学习网络上的文章时的总结以及自己的一点实践.感谢大家无私的分享. 近期偶然遇到了数组的问题,学习了匿名数组和不规则数组. 匿名数组适用于仅仅使用一次的情况:不规则数组适用是每行数据总数不确定的情 ...
- Perl关联数组用法集锦
本文和大家重点讨论一下Perl关联数组的概念,创建Perl关联数组,从数组变量复制到Perl关联数组,元素的增删,用Perl关联数组循环等内容,相信通过本文的学习你对Perl关联数组的用法一定会有深刻 ...
- bzoj 1669: [Usaco2006 Oct]Hungry Cows饥饿的奶牛【dp+树状数组+hash】
最长上升子序列.虽然数据可以直接n方但是另写了个nlogn的 转移:f[i]=max(f[j]+1)(a[j]<a[i]) O(n^2) #include<iostream> #in ...
- PHP数组/Hash表的实现/操作、PHP变量内核实现、PHP常量内核实现 - [ PHP内核学习 ]
catalogue . PHP Hash表 . PHP数组定义 . PHP变量实现 . PHP常量实现 1. PHP Hash表 0x1: 基本概念 哈希表在实践中使用的非常广泛,例如编译器通常会维护 ...
- perl 判断数组相等的三种方法
1.数组相等,数组成员相同,位置也相同 一般的如果判断@array1 等于 @array2 a.数组长度相同 $#array1=$#array2, 比较数组长度,不能使用length函数,length ...
- Perl中的hash类型
hash类型 hash类型也称为字典.关联数组.映射(map)等等,其实它们都是同一种东西:键值对.每一个Key对应一个Value. hash会将key/value散列后,按序放进hash桶.散列后的 ...
- [Perl] 删除数组中重复元素
写一个小程序时候,需要去除一个数组中的重复元素,搜索了一下,找到的代码主要是两种,一种是使用grep函数,一种是转换为hash表,代码分别如下: 使用grep函数代码片段:代码: my @array ...
随机推荐
- python csv读写
https://blog.csdn.net/taotiezhengfeng/article/details/75577998
- 网页偶现性崩溃-chrome
简介: 项目前台框架:Angular2 + Bootstrap(日期等组件) + Echarts + 响应式(包括页面.字体缩放:rem) chrome版本:多个版本测试均有此问题. 表现: 订单详情 ...
- jwt vs session 以rails 为例 (翻译部分)
原文地址:https://pragmaticstudio.com/tutorials/rails-session-cookies-for-api-authentication 普通方式: 令牌为基础的 ...
- uc/osⅡ/Ⅲ
1.关于任务堆栈时#if在main()中的用法: #if ... #else#endif//与#if对应作为一个编译“开关”,比如#if(条件满足) 执行代码1 #else 执行代码2 #endif ...
- Redis-03.事务
Redis事务: 在一个队列(queue)中依次执行一系列的命令. 事务的三个阶段: 1.开始事务(MULTI) 2.命令加入队列 (QUEUE) 3.执行事务 (EXEC) 示例1: MULTI & ...
- 【腾讯Bugly干货分享】Android 新一代多渠道打包神器
关于作者: 李涛,腾讯Android工程师,14年加入腾讯SNG增值产品部,期间主要负责手Q动漫.企鹅电竞等项目的功能开发和技术优化.业务时间喜欢折腾新技术,写一些技术文章,个人技术博客:www.lt ...
- 腾讯技术分享:微信小程序音视频技术背后的故事
1.引言 微信小程序自2017年1月9日正式对外公布以来,越来越受到关注和重视,小程序上的各种技术体验也越来越丰富.而音视频作为高速移动网络时代下增长最快的应用形式之一,在微信小程序中也当然不能错过. ...
- C++ Opencv 傅里叶变换的代码实现及关键函数详解
一.前言 最近几天接触了图像的傅里叶变换,数学原理依旧不是很懂,因此不敢在这里妄言.下午用Opencv代码实现了这一变换,有一些经验心得,愿与大家分享. 二.关键函数解析 2.1copyMakeBor ...
- Mycat入门
1. Mycat入门 官网 http://www.mycat.io/ 1.1. 什么是Mycat 一个彻底开源的,面向企业应用开发的大数据库集群 支持事务.ACID.可以替代MySQL的加强版数据库 ...
- 传参导出Excel表乱码问题解决方法
业务场景 先描述一下业务场景,要实现的功能是通过搜索框填写参数,然后点击按钮搜索数据,将搜索框的查询参数获取,附加在链接后面,调导Excel表接口,然后实现导出Excel功能.其实做导Excel表功能 ...