使用引用可以指向数据对象,这似乎很简单。

  1. @name1=qw(longshuai wugui);
  2. @name2=qw(xiaofang tuner);
  3. $ref_name=\@name1;
  4. push @name2,$ref_name;
  5. print "@name2"; # 输出:xiaofang tuner ARRAY(0xNAME1)

但如果想通过引用的方式取出数据对象的值呢,就像上面的print语句中,想要输出@name2中包含的@name1的元素,而不是它的地址空间。这需要解除引用(dereference),将$ref_name引用还原为数据对象qw(longshuai wugui)

前方预警:dereference虽然不难,但初学之时,比较烧脑,比较眼晕

解除数组的引用

在解释引用解除之前,有必要先解释下引用符号和数据对象的名称。

创建一个@name=qw(value1 value2 value3)的数组,这个数组初始化时,数组名为name,它是这个列表数据对象的第一个引用(注意,数组名是引用),引用方式为@符号+数组名name,即@name。实际上,真正规范的引用方式为@{name}

因此,当使用引用变量的方式引用数据对象时,只需把数组名称换成引用变量的名称即可(它们是等价的,都是对数据对象的引用),再加上@符号即可,因为数组名称和引用变量的名称都是指向数据对象的名称。

例如,将@name的引用赋值给一个引用变量$ref_name后(即$ref_name=\@name),就可以使用@$ref_name的方式来表示解除引用,它和@name是等价的关系。

以下几种引用方式绝大多数时候是等价的,可以用来做参考、对应。其实很好理解,只要把原本的对象名称,替换成引用变量的名称即可。

  1. @{name} --> @{$ref_name}
  2. @{ name } --> @{ $ref_name }
  3. @name --> @$ref_name

如果引用变量的名称有特殊符号,例如以$符号作为变量名的开头符号,则不能省略大括号。当然,这种情况基本不会出现,因为不符合命名规范,没人会自找麻烦。

例如:

  1. #!/usr/bin/perl
  2. use 5.010;
  3. @name=qw(longshuai wugui);
  4. $ref_name=\@name;
  5. say "@{$ref_name}";
  6. say "@{ $ref_name }";
  7. say "@$ref_name";

解除hash的引用

同理,解除hash的引用同解除数组引用的方式一样,使用引用符号%+引用的名称即可。

例如,创建一个hash:%myhash,其中myhash是hash数据对象的名称,%是hash的引用符号。创建一个hash的引用变量$ref_myhash=\%myhash,那么引用变量对应的是hash的名称myhash,所以通过引用变量名来解除hash引用时:%$ref_myhash即可。

以下是几种等价的引用方式:

  1. %{name} --> %{$ref_name}
  2. %{ name } --> %{ $ref_name }
  3. %name --> %$ref_name

例如:

  1. #!/usr/bin/perl
  2. use 5.010;
  3. %myhash=(
  4. longshuai => "18012345678",
  5. xiaofang => "17012345678",
  6. wugui => "16012345678",
  7. tuner => "15012345678"
  8. );
  9. $ref_myhash =\%myhash;
  10. say %$ref_myhash;

解除引用:取数组、hash中的元素(1)

对于普通的数组和hash,取得它们数据对象中的元素方式为:

  1. $arr_name[1] # 取得数组中的第二个元素
  2. ${arr_name}[1] # 取得数组中的第二个元素
  3. $hash_name{'mykey'} # 取得hash中key为'mykey'的value
  4. ${hash_name}{'mykey'} # 取得hash中key为'mykey'的value

那么使用引用的方式来获取数组、hash中的元素时,方式是一样的,只需将引用变量替换为对应的数据对象名称即可。

例如:

  1. # 数组元素的引用
  2. ${name}[1] -> ${$ref_name}[1]
  3. ${ name }[1] -> ${ $ref_name }[1]
  4. $name[1] -> $$ref_name[1]
  5. # hash元素的引用
  6. ${myhash}{'wugui'} -> ${$ref_myhash}{'wugui'}
  7. ${ myhash }{'wugui'} -> $ {$ref_myhash }{'wugui'}
  8. $myhash{'wugui'} -> $$ref_myhash{'wugui'}

例如:

  1. #!/usr/bin/perl
  2. use 5.010;
  3. # 取数组的元素
  4. @name=qw(longshuai wugui);
  5. $ref_name=\@name;
  6. say "${$ref_name}[1]";
  7. say "${ $ref_name }[1]";
  8. say "$$ref_name[1]";
  9. # 取hash的元素
  10. %myhash=(
  11. longshuai => "18012345678",
  12. xiaofang => "17012345678",
  13. wugui => "16012345678",
  14. tuner => "15012345678"
  15. );
  16. $ref_myhash =\%myhash;
  17. say "${$ref_myhash}{'wugui'}";
  18. say "${ $ref_myhash }{'wugui'}";
  19. say "$$ref_myhash{'wugui'}";

解除引用:取数组、hash中的元素(2)

除了上面的介绍的取元素方法,对于引用变量,还支持更简洁的"瘦箭头"指向法:只需使用引用变量名->元素索引即可。注意,箭头两边必须不能有空格。

  1. $ref_name->[1]
  2. $ref_myhash->{'mykey'}

如此一来,取元素的写法变得简洁易读,且可以规范化,也不会再出现一大堆容易让人疑惑的符号。当然,到目前为止都只是简单的引用方式,稍后介绍如何取复杂数据结构的元素时,将会看到不用箭头的方式取数据将非常伤眼睛。

关于瘦箭头取元素的用法,给个简单的示例:

  1. #!/usr/bin/perl
  2. use 5.010;
  3. @name=qw(longshuai wugui);
  4. $ref_name=\@name;
  5. say "$ref_name->[0]";
  6. %myhash=(
  7. longshuai => "18012345678",
  8. xiaofang => "17012345678",
  9. wugui => "16012345678",
  10. tuner => "15012345678"
  11. );
  12. $ref_myhash =\%myhash;
  13. say "$ref_myhash->{'wugui'}";

取复杂数据结构中的元素

对于复杂数据结构,想要取它的元素并非那么容易。例如,hash的value中有数组作为元素,该数组元素中又有数组的时候。

CPAN::Config的一部分内容为例:

  1. #!/usr/bin/perl
  2. use 5.010;
  3. %Config = (
  4. 'auto_commit' => '0',
  5. 'build_dir' => '/home/fairy/.cpan/build',
  6. 'bzip2' => '/bin/bzip2',
  7. 'urllist' => [
  8. 'http://cpan.metacpan.org/',
  9. \@my_urllist # 将数组my_urllist作为元素
  10. ],
  11. 'wget' => '/usr/bin/wget',
  12. );
  13. $ref_Config=\%Config;
  14. @my_urllist=('http://mirrors.aliyun.com/CPAN/',
  15. 'https://mirrors.tuna.tsinghua.edu.cn/CPAN/',
  16. 'https://mirrors.163.com/cpan/',
  17. \@more_urllist # 将数组more_urllist引用作为元素
  18. );
  19. @more_urllist=qw(http://mirrors.shu.edu.cn/CPAN/
  20. http://mirror.lzu.edu.cn/CPAN/
  21. );

以下是使用原始取得more_urllist数组中第2个元素的方式:

  1. say "${$ref_Config}{'urllist'}"; # 取得key=urllist对应的value:数组
  2. say "${$ref_Config}{'urllist'}[1]"; # 取得urllist数组中第二个元素:\@my_urllist引用
  3. say "${$ref_Config}{'urllist'}[1][3]"; # 取得my_urllist数组中第4个元素:\@more_urllist引用
  4. say "${$ref_Config}{'urllist'}[1][3][1]"; # 取得more_urllist数组中第2个元素

其实上面的写法不是完全规范写法,因为每次取得引用后,都没有对应于进行${$REF}的规范化。以下是与上面完全对应的规范写法:

  1. say "${$ref_Config}{'urllist'}";
  2. say "${$ref_Config}{'urllist'}[1]"; # 取得引用
  3. say "${${$ref_Config}{'urllist'}[1]}[3]"; # 再次取得引用
  4. say "${${${$ref_Config}{'urllist'}[1]}[3]}[1]"; # 最终取得元素

啊,我的眼睛,受不了,受不了。

如果使用瘦箭头引用方式,则更简洁易读:

  1. say "$ref_Config->{'urllist'}";
  2. say "$ref_Config->{'urllist'}->[1]";
  3. say "$ref_Config->{'urllist'}->[1]->[3]";
  4. say "$ref_Config->{'urllist'}->[1]->[3]->[1]";

各元素之间的瘦箭头可以省略(引用变量名称和元素之间的箭头必须不能省略)。

  1. say "$ref_Config->{'urllist'}";
  2. say "$ref_Config->{'urllist'}[1]";
  3. say "$ref_Config->{'urllist'}[1][3]";
  4. say "$ref_Config->{'urllist'}[1][3][1]";

最后需要特别说明的是,当将复杂数据结构的引用当作子程序的参数传给@_时,甚至是@_的一部分时,要特别小心地写,一个不小心就错了。

例如,子程序传递的参数形式如下:

  1. mysub('aaa',\%Config)

那么要在子程序内部取得more_urllist中的第二个元素,子程序中取元素相关的代码大致如下:

  1. my $first_arg = shift @_;
  2. say "${$_[0]}{'urllist'}"; # 等价于:$_[0]->{'urllist'}
  3. say "${$_[0]}{'urllist'}[1][3][1]"; # 等价于:$_[0]->{'urllist'}[1][3][1]

只需搞明白,@_中的元素使用$_[N]获取,而$_[N]获取到的可能是以一个引用,所以将其当作引用变量名即可。

Perl解除引用:从引用还原到数据对象的更多相关文章

  1. C++ primer(八)--内联函数 引用变量 引用传递函数参数 函数重载/模板/模板具体化

    一.内联函数     常规函数和内联函数的区别在于C++编译器如何将他们组合到程序中.编译过程的最终产品是可执行程序--由一组机器语言指令组成.运行程序时,操作系统将这些指令载入到计算机内存中,因此每 ...

  2. perl 为什么要用引用来做对象呢?

    perl 为什么要用引用来做对象呢? 因为一个重要的原因是 my 引用 脱离作用域,外部仍旧生效

  3. JavaScript 类的定义和引用 JavaScript高级培训 自定义对象

    在Java语言中,我们可以定义自己的类,并根据这些类创建对象来使用,在Javascript中,我们也可以定义自己的类,例如定义User类.Hashtable类等等.     一,概述 在Java语言中 ...

  4. Java 多个引用类型变量引用同一个对象

    引用类型变量在声明后必须引用对象才能使用. 一个引用变量只能唯一指向一个对象,但同一个对象可被多个引用类型变量引用. 如:MyDate today; //将变量跟配给一个保存引用的空间(栈) toda ...

  5. 从list引用调用arraylist和linkedlist对象的方法了解多态

    一.前言 今天和朋友在写代码时突然发现List<object>  list=new ArrayList<object>()中,前面是通过List引用来调用其子类ArrayLis ...

  6. instanceof关键字用于判断一个引用类型变量所指向的对象是否是一个类(或接口、抽象类、父类)的实例。

    http://lavasoft.blog.51cto.com/62575/79864/    深入Java关键字instanceof 2008-06-02 07:50:43 标签:Java 关键字 休 ...

  7. ASP.NET真分页_接前篇引用AspNetPager.dll进行数据分页

    一.前端准备工作 1.之前我写到过<Asp.net中引用AspNetPager.dll进行数据分页>  这种分页方式只能在前台将数据分页,而每次点击查询时对目标数据库还是全查询,这样不仅会 ...

  8. NDK开发之引用(局部引用,全局引用,虚全局引用)

    1.先引出我遇到的一个问题(我觉得先写问题,这样印象更深刻一点): Android Java层在调用本地jni代码的时候, 会维护一个局部引用表(最大长度是512), 一般jni函数调用结束后, jv ...

  9. Java -强引用&弱引用

    ⑴强引用(StrongReference) 就是通过new得的对象引用 强引用是使用最普遍的引用.如果一个对象具有强引用,那垃圾回收器绝不会回收它.当内存空间不足,Java虚拟机宁愿抛出OutOfMe ...

随机推荐

  1. asp.net动态加载程序集创建指定类的实例及调用指定方法

    以下类中有三个方法: LoadAssembly:加载指定路径的程序集 GetInstance:根据Type动态获取实例,用泛型接到返回的类型 ExecuteMothod:执行实例中的指定方法 /// ...

  2. HTTP一、HTTP介绍与套接字

    目录 一.套接字 1.HTTP与Apache 2.应用层协议:HTTP 3.套接字(IP+协议端口的组合) 4.套接字图示 5.套接字相关知识点 二.HTTP         一.套接字     1. ...

  3. Codeforces Avito Code Challenge 2018 D. Bookshelves

    Codeforces Avito Code Challenge 2018 D. Bookshelves 题目连接: http://codeforces.com/contest/981/problem/ ...

  4. Python数据结构之单链表

    Python数据结构之单链表 单链表有后继结点,无前继结点. 以下实现: 创建单链表 打印单链表 获取单链表的长度 判断单链表是否为空 在单链表后插入数据 获取单链表指定位置的数据 获取单链表指定元素 ...

  5. Equal 路由类

    1.Route 原型 class Route { /* 获取请求路径和查询字符串 */ /* 获取模块.控制器.动作名称 */ /* 获取 URI 参数 */ }

  6. (1)selenium-java环境搭建

    已经学过了用python模拟浏览器操作,现在开始尝试使用java搭建环境,开头第一步就遇到了很多的问题 1.准备jdk安装,不再描述,自行百度 2.安装eclipse 3.接下来就是新建项目了,new ...

  7. POJ2391 Ombrophobic Bovines

    Ombrophobic Bovines Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 19359   Accepted: 4 ...

  8. openvpn搭建和使用

    一.openvpn原理 openvpn通过使用公开密钥(非对称密钥,加密解密使用不同的key,一个称为Publice key,另外一个是Private key)对数据进行加密的.这种方式称为TLS加密 ...

  9. day17_雷神_数据库 小全

    # 数据库 1.mysql 介绍 一 数据库管理软件的由来 程序的所有组件不可能只在一个机子上,性能问题和单点故障, 程序分散了,还需要解决数据共享问题, 基于网络访问这台共享的机器,用socket. ...

  10. rem计算

    //jquery实现 // $(function(){ // $(window).on("resize",function(){ // var width=$(window).wi ...