5

我在这里有一个关于 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   
                   ]   
                 ]   
        }   

任何帮助表示赞赏。提前致谢!
-担

4

4 回答 4

4

这不是对$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.

顺便说一句,您可能会发现使用符号[ ... ]{ ... }创建对匿名数组和散列的引用(分别)很有帮助。由于您从不使用@a1and@a2除了通过$a1_refand $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];
}
于 2013-05-04T19:41:16.773 回答
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 ];
    }

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

于 2013-05-04T20:08:23.927 回答
2

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

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

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

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

您希望每个哈希值都是对一个二元素数组的引用,每个数组都是对另一个包含来自@a1and的数据的数组的引用@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]],
}
于 2013-05-04T20:30:50.070 回答
0

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

于 2013-05-09T23:01:00.150 回答