【问题标题】:how to use perl references correctly如何正确使用 perl 引用
【发布时间】:2013-05-04 19:35:29
【问题描述】:

我在这里有一个关于 refs 的非常菜鸟的问题,但至少仍然让我感到困惑......
在下面的代码示例中,我正在尝试创建数组哈希:

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;
use Data::Dumper;

$Data::Dumper::Sortkeys = 1;
$Data::Dumper::Terse = 1;
$Data::Dumper::Quotekeys = 0;

my @a1 = ( 'a1', 1, 1, 1 );
my @a2 = ( 'a2', 2, 2, 2 );

my $a1_ref = \@a1;
my $a2_ref = \@a2;

my @a = ( $a1_ref, $a2_ref );

my %h = ();

for my $i ( 1 .. 2 ) {
        $h{"$i"} = \@a;
}

say Dumper \%h;

Dumper 输出为

{
          '1' => [
                   [
                     'a1',
                     1,
                     1,
                     1
                   ],
                   [
                     'a2',
                     2,
                     2,
                     2
                   ]
                 ],
          '2' => $VAR1->{'1'}
        }

这里的问题是:
为什么 $h{'2'} 是对 $h{'1'} 的引用?我正在尝试使用由@a 数组组成的相同键值创建一个哈希 %h。我希望散列的每个键值都有它自己的基于@a 的 AoA,但我得到的是对 $h{'1'} 的引用。我做错了什么??
我想要达到的 Dumper 输出是:

{
          '1' => [
                   [   
                     'a1',
                     1,  
                     1,  
                     1   
                   ],  
                   [   
                     'a2',
                     2,  
                     2,  
                     2   
                   ]   
                 ],  
          '2' => [
                   [   
                     'a1',
                     1,  
                     1,  
                     1   
                   ],  
                   [   
                     'a2',
                     2,  
                     2,  
                     2   
                   ]   
                 ]   
        }   

任何帮助表示赞赏。在此先感谢!
-丹

【问题讨论】:

    标签: perl reference


    【解决方案1】:

    并不是$h{'2'} 是对$h{'1'} 的引用,而是两者都是对同一个数组的引用,即@a。你可能想要的是:

    for my $i ( 1 .. 2 ) {
        $h{"$i"} = $a[$i - 1];
    }
    

    相当于这个:

    $h{'1'} = $a[0];   # i.e., $a1_ref
    $h{'2'} = $a[1];   # i.e., $a2_ref
    

    这使得$h{'1'} 引用@a1$h{'2'} 引用@a2

    顺便说一句,您可能会发现使用符号[ ... ]{ ... }(分别)创建对匿名 数组和散列的引用很有帮助。由于您从不使用@a1@a2,除了通过$a1_ref$a2_ref,您不妨直接创建后者:

    my $a1_ref = [ 'a1', 1, 1, 1 ];   # reference to a new array (no name needed)
    my $a2_ref = [ 'a2', 2, 2, 2 ];   # ditto
    

    编辑更新问题:要复制数组,您可以编写:

    my @orig = (1, 2, 3);
    my @new = @orig;
    

    或:

    my $orig_ref = [1, 2, 3];
    my $new_ref = [@$orig_ref]; # arrayref -> array -> list -> array -> arrayref
    

    在你的情况下,如果我理解正确,你需要执行一个稍微“深”的复制:你不只是想要两个具有相同元素的数组,你想要两个数组,其元素是对不同数组的引用相同的元素。没有内置的 Perl 方法可以做到这一点,但您可以编写一个循环,或使用 map 函数:

    my @orig = ([1, 2, 3], [4, 5, 6]);
    my @new = map [@$_], @orig;
    

    所以:

    for my $i ( 1 .. 2 ) {
        $h{"$i"} = [map [@$_], @a];
    }
    

    【讨论】:

    • 感谢@ruakh,但这并不是我想要实现的。我已经用更多信息更新了我的帖子。这是关于参考符号的一个很好的提示。
    【解决方案2】:

    这(你在做什么)将使$h{1}$h{2} 引用同一个数组@a

        for my $i ( 1 .. 2 ) {
            $h{"$i"} = \@a;
        }
    

    这将使$h{1}$h{2} 引用两个不同的对象,每个对象@a 的副本

        for my $i ( 1 .. 2 ) {
            $h{"$i"} = [ @a ];
        }
    

    但是内部数组仍然会被别名。听起来你想要一个深拷贝

    【讨论】:

      【解决方案3】:

      我认为这段代码可以满足您的需求。

      我已切换到Data::Dump,因为我更喜欢它的输出。

      引用数据的问题在于,无论您复制多少次该引用,它仍然指向相同的数据,因此该数据的更改会在所引用的任何地方反映出来。

      要生成第二个独立副本,例如数组,您当然可以编写 my @copy = @array 并从那里开始工作。但是使用[ @array ] 很方便,它将数组的内容复制到一个新的匿名数组并返回对它的引用。

      您希望每个哈希值都是对一个二元素数组的引用,每个数组都是对另一个数组的引用,该数组包含来自@a1@a2 的数据。此代码将为您完成。

      另外一点是,由于散列键是字符串,因此对它们使用数值是不常见的:它表明您应该使用数组来代替。但由于所有这些显然都是占位符数据,我并不太担心。

      use strict;
      use warnings;
      
      use Data::Dump;
      
      my @a1 = qw/ a1 1 1 1 /;
      my @a2 = qw/ a2 2 2 2 /;
      
      my %h;
      
      for my $i ( 1, 2 ) {
        $h{$i} = [ [ @a1 ], [ @a2 ] ];
      }
      
      dd \%h;
      

      输出

      {
        1 => [["a1", 1, 1, 1], ["a2", 2, 2, 2]],
        2 => [["a1", 1, 1, 1], ["a2", 2, 2, 2]],
      }
      

      【讨论】:

        【解决方案4】:

        以上所有答案都为我指出了正确的解决方案(和问题)。这就是需要复制结构然后使用对它的引用。我在这里指出的数组和哈希只是更复杂结构的占位符。因此,为了制作结构的副本,我使用了Clone 模块,它完全复制了结构并返回对它的不同引用。 谢谢大家的回复!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-06-30
          • 1970-01-01
          • 2014-10-17
          • 2020-09-17
          • 1970-01-01
          • 1970-01-01
          • 2023-04-10
          • 1970-01-01
          相关资源
          最近更新 更多