如何正确使用Perl引用

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;

转储器输出如下:
{
          '1' => [
                   [
                     'a1',
                     1,
                     1,
                     1
                   ],
                   [
                     'a2',
                     2,
                     2,
                     2
                   ]
                 ],
          '2' => $VAR1->{'1'}
        }

这里的问题是:
为什么$h{'2'}是$h{'1'}的引用?我试图创建一个哈希%h,其中每个键值都由@a数组中的数组组成。我想让哈希的每个键值都有它自己基于@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

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

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_ref$a2_ref之外从未使用过@a1@a2,因此您可以直接创建后者:

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,但那不是我想要实现的。我已经在我的帖子中更新了更多信息。关于引用符号的提示很好。 - Gnowl

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]],
}

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接