如何正确使用perl引用

时间:2013-05-04 19:35:30

标签: perl reference

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

#!/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'}。我做错了什么? 我试图实现的翻车机输出是:

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

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

4 个答案:

答案 0 :(得分: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

顺便说一下,您可能会发现使用符号[ ... ]{ ... }创建对匿名数组和哈希(分别)的引用会很有帮助。由于除了@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];
}

答案 1 :(得分: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 ];
    }

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

答案 2 :(得分:2)

我认为这段代码符合您的要求。

我已切换到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]],
}

答案 3 :(得分:0)

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