zoukankan      html  css  js  c++  java
  • 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虽然不难,但初学之时,比较烧脑,比较眼晕

    解除数组的引用

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

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

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

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

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

         @{name}    --> @{$ref_name}
         @{ name }  --> @{ $ref_name }
         @name      --> @$ref_name
    

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

    例如:

    #!/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]获取到的可能是以一个引用,所以将其当作引用变量名即可。

  • 相关阅读:
    Documents
    gitlab 安装和配置
    git相关知识
    马俊龙ansible教程分享
    源码安装python 报错,openssl: error while loading shared libraries: libssl.so.1.1
    jumpserver 常见错误解决
    nginx 定义:响应头和请求头
    gcc入门(下)
    gcc入门(上)
    awk命令
  • 原文地址:https://www.cnblogs.com/f-ck-need-u/p/9710562.html
Copyright © 2011-2022 走看看