为了找到我之前的问题Perl: slicing an array of hashes的答案,我再次陷入困境,无法看到我做错了什么。
我拥有的是
数组(Array0(Hash0,Hash1),Array1(Hash0,Hash1),Array2(Hash0,Hash1)......)
use strict;
use warnings;
my @DDs = ();
my @Ds = ();
my %hsh = ();
my %dot1 = ( 'x' => 1, 'y' => 2, 'r' => 3 );
my %dot2 = ( 'x' => 4, 'y' => 5, 'r' => 6 );
my %dot3 = ( 'x' => 7, 'y' => 8, 'r' => 9 );
my %dot4 = ( 'x' => 1.1, 'y' => 1.2, 'r' => 1.3 );
my %dot5 = ( 'x' => 2.1, 'y' => 2.2, 'r' => 2.3 );
my %dot6 = ( 'x' => 3.1, 'y' => 3.2, 'r' => 3.3 );
my %dot7 = ( 'x' => 4.1, 'y' => 4.2, 'r' => 4.3 );
my %dot8 = ( 'x' => 5.1, 'y' => 5.2, 'r' => 5.3 );
my @dotsA = ( \%dot1, \%dot2 );
my @dotsB = ( \%dot3, \%dot4 );
my @dotsC = ( \%dot5, \%dot6 );
my @dotsD = ( \%dot7, \%dot8 );
my %Ds = ( \@dotsA, \@dotsB, \@dotsC, \@dotsD );
@DDs = $Ds[1]; #expect @dotsB with scalar of 2
###"Can't use an undefined value as HASH reference" error here
%hsh = %{ $DDs[0] }; #expect %dot3
print scalar @DDs, "\n"; #expect 2 but has value of 1
print $hsh{'x'}, "\n";
答案 0 :(得分:6)
参考文献找到了/Users/schwern/tmp/test.plx第10行的预期大小列表。
第10行是这样的:
my %dot1 = {'x'=>1,'y'=>2,'r'=>3};
这是Perl的一种神秘的方式,说你给哈希提供了一个哈希引用。不幸的是,Perl在事物和对事物的引用之间存在很大差异。
%dot1
是一个哈希值。它需要一个列表并将其转换为哈希值。像( x => 1, y => 2, r => 3)
这样的列表。 { x => 1, y => 2, r => 3 }
创建哈希引用。这是一个单一的东西,一个标量。这就像说my %dot1 = (42)
。这没有任何意义。
(x => 1, y => 2)
{ x => 1, y => 2 }
这样的哈希引用。my %Ds = (\@dotsA,\@dotsB,\@dotsC,\@dotsD);
散列需要键和值,对。 last_name => "Schwern"
。当你给它一堆像这样的数组引用时,它会将它们读作key1,value1,key2,value2 ......但是它用作键是什么?它正在使用该引用的字符串化,例如ARRAY(0x7fb721800468)
。
如果您要求$D{\@dotsA}
,您将获得对@dotsB
的引用。您将无法返回@dotsA
,Perl哈希键只是一个字符串,而不是引用。
这不是一个在哈希中存储数组的好方法。我不确定你要完成什么,但你可能想要通过名字来引用它们。
# A hash of lists.
my %Ds = ( A => \@dotsA, B => \@dotsB, C => \@dotsC, D => \@dotsD );
# Get back a reference to @dotsA.
my $dotsA = $Ds{A};
但是查看以下代码@DDs = $Ds[1];
,我认为您打算初始化@Ds
而不是%Ds
。
@Ds = (\@dotsA,\@dotsB,\@dotsC,\@dotsD);
现在以下作品......有点儿。更晚些时候。
@DDs = $Ds[1]; #expect @dotsB with scalar of 2
与PHP不同,哈希和数组是完全不同的东西。 my @Ds
和my %Ds
声明了完全不同的变量。使用$Ds
访问它们无关紧要。在Perl5中,sigil表示将返回什么。 $Ds[1]
和$Ds{foo}
都使用$Ds
因为它们返回标量。 @Ds[1,2]
和@Ds{(foo, bar)}
使用@Ds
因为他们返回了一个列表(称为切片)。令人困惑,但这就是它的工作原理。
@DDs = $Ds[1]; #expect @dotsB with scalar of 2
您未获得@dotsB
,而是获得对@dotsB
的引用。 Perl中的所有复杂数据结构都存储引用,而不是实际值。这就像$DDs[0] = \@dotsB
。如果你想获得实际值,你必须取消引用它。
@DDs = @{$Ds[1]}; # Now @DDs has a copy of @dotsB
最后它有效。
#!/usr/bin/perl
use strict;
use warnings;
use v5.10; # for say()
my %dot1 = ('x'=>1,'y'=>2,'r'=>3);
my %dot2 = ('x'=>4,'y'=>5,'r'=>6);
my %dot3 = ('x'=>7,'y'=>8,'r'=>9);
my %dot4 = ('x'=>1.1,'y'=>1.2,'r'=>1.3);
my %dot5 = ('x'=>2.1,'y'=>2.2,'r'=>2.3);
my %dot6 = ('x'=>3.1,'y'=>3.2,'r'=>3.3);
my %dot7 = ('x'=>4.1,'y'=>4.2,'r'=>4.3);
my %dot8 = ('x'=>5.1,'y'=>5.2,'r'=>5.3);
my @dotsA = (\%dot1,\%dot2);
my @dotsB = (\%dot3,\%dot4);
my @dotsC = (\%dot5,\%dot6);
my @dotsD = (\%dot7,\%dot8);
my @Ds = (\@dotsA,\@dotsB,\@dotsC,\@dotsD);
my @DDs = @{$Ds[1]}; #expect @dotsB
my %hsh = %{$DDs[0]}; #expect %dot3
say scalar @DDs; #expect 2
say $hsh{'x'};
我还建议您直接使用引用,因为这就是复杂的数据结构:引用。从引用到值的来回转换是令人困惑的。使用引用只需要在代码中转换,在头脑中转换,并减少在程序中完成的复制。
#!/usr/bin/perl
use strict;
use warnings;
use v5.10; # for say()
my $dot1 = {'x'=>1,'y'=>2,'r'=>3};
my $dot2 = {'x'=>4,'y'=>5,'r'=>6};
my $dot3 = {'x'=>7,'y'=>8,'r'=>9};
my $dot4 = {'x'=>1.1,'y'=>1.2,'r'=>1.3};
my $dot5 = {'x'=>2.1,'y'=>2.2,'r'=>2.3};
my $dot6 = {'x'=>3.1,'y'=>3.2,'r'=>3.3};
my $dot7 = {'x'=>4.1,'y'=>4.2,'r'=>4.3};
my $dot8 = {'x'=>5.1,'y'=>5.2,'r'=>5.3};
my $dotsA = [$dot1,$dot2];
my $dotsB = [$dot3,$dot4];
my $dotsC = [$dot5,$dot6];
my $dotsD = [$dot7,$dot8];
my $Ds = [$dotsA,$dotsB,$dotsC,$dotsD];
my $DDs = $Ds->[1]; #expect $dotsB
my $hsh = $DDs->[0]; #expect $dot3
say scalar @$DDs; #expect 2
say $hsh->{'x'};
您应该查看perlreftut和Nested Data Structures chapter of Modern Perl。