下面的代码工作正常,但如果我用push @array,{%hash}
替换push @array,\%hash
,那么它就没有了。有人可以帮我理解差异。我相信{%hash}
是指匿名哈希。这是否意味着匿名哈希的存在时间长于对命名哈希(\%hash
)的引用。
use strict;
use warnings;
use Data::Dumper;
my @array;
my %hash;
%hash = ('a' => 1,
'b' => 2,
'c' => 3,);
push @array,{%hash};
%hash = ('e' => 1,
'f' => 2,
'd' => 3,);
push @array,{%hash};
print Dumper \@array;
输出
$VAR1 = [
{
'c' => 3,
'a' => 1,
'b' => 2
},
{
'e' => 1,
'd' => 3,
'f' => 2
}
];
更新 以下是我正在处理的实际代码。我认为在这种情况下,参考的副本是我认为唯一可行的解决方案。如果我错了,请纠正我。
use Data::Dumper;
use strict;
use warnings;
my %csv_data;
my %temp_hash;
my @cols_of_interest = qw(dev_file test_file diff_file status);
<DATA>; #Skipping the header
while (my $row = <DATA>) {
chomp $row;
my @array = split /,/,$row;
@temp_hash{@cols_of_interest} = @array[3..$#array];
push @{$csv_data{$array[0]}{$array[1] . ':' . $array[2]}},{%temp_hash};
}
print Dumper \%csv_data;
__DATA__
dom,type,id,dev_file,test_file,diff_file,status
A,alpha,1234,dev_file_1234_1.txt,test_file_1234_1.txt,diff_file_1234_1.txt,pass
A,alpha,1234,dev_file_1234_2.txt,test_file_1234_2.txt,diff_file_1234_2.txt,fail
A,alpha,1234,dev_file_1234_3.txt,test_file_1234_3.txt,diff_file_1234_3.txt,pass
B,beta,4567,dev_file_4567_1.txt,test_file_4567_1.txt,diff_file_4567_1.txt,pass
B,beta,4567,dev_file_4567_2.txt,test_file_4567_2.txt,diff_file_4567_2.txt,fail
C,gamma,3435,dev_file_3435_1.txt,test_file_3435_1.txt,diff_file_3435_1.txt,pass
D,hexa,6768,dev_file_6768_1.txt,test_file_6768_1.txt,diff_file_6768_1.txt,fail
答案 0 :(得分:13)
\%hash
和{%hash}
都会创建引用,但它们引用了两个不同的东西。
\%hash
是对%hash
的引用。如果取消引用,其值将随%hash
中的值而变化。
{%hash}
根据%hash
中的值创建新的匿名哈希引用。它会创建副本。这是在Perl中创建shallow copy数据结构的最简单方法。如果您更改%hash
,则此副本不会受到影响。
变量的存在时间与变量的类型或创建方式无关。只有scope与此相关。 Perl中的引用在这里是一个特殊情况,因为有一个内部引用计数器可以跟踪对值的引用,因此如果某个地方仍有引用,即使它超出范围,它也会保持活动状态。这就是为什么这样做的原因:
sub frobnicate {
my %hash = ( foo => 'bar' );
return \%hash;
}
如果您想要将参考与初始值取消关联,则需要通过weak reference通过weaken
将其转换为Scalar::Util。这样,引用计数不会受其影响,但它仍然与值相关,而副本则不会。
有关参考资料的详情,请参阅perlref和perlreftut。 This question处理如何查看引用计数。有关这方面的说明,请参见Reference Counts and Mortality in perlguts一章。
答案 1 :(得分:3)
您无法真正将\
与{}
和[]
进行比较,因为它们根本不会做同样的事情。
{ LIST }
是my %anon = LIST; \%anon
[ LIST ]
是my @anon = LIST; \@anon
也许你打算比较
my %hash = ...;
push @a, \%hash;
push @a, { ... };
my %hash = ...;
push @a, { %hash };
第一个代码段在%hash
中引用@a
的引用。这可能是在一个循环中找到的。只要在循环中找到my %hash
,每次都会在@a
中放置对新哈希的引用。
第二个片段也是如此,只使用匿名哈希。
第三个代码段会复制%hash
,并在@a
中放置对该副本的引用。它给人的印象是浪费,所以不要气馁。 (实际上并不浪费,因为它允许重用%hash
。)
您也可以编写代码
# In reality, the two blocks below are probably the body of one sub or one loop.
{
my %hash = (
a => 1,
b => 2,
c => 3,
);
push @a, \%hash;
}
{
my %hash = (
d => 3,
e => 1,
f => 2,
);
push @a, \%hash;
}
或
push @a, {
a => 1,
b => 2,
c => 3,
};
push @a, {
d => 3,
e => 1,
f => 2,
};
my @cols_of_interest = qw( dev_file test_file diff_file status );
my %csv_data;
if (defined( my $row = <DATA> )) {
chomp $row;
my @cols = split(/,/, $row);
my %cols_of_interest = map { $_ => 1 } @cols_of_interest;
my @cols_to_delete = grep { !$cols_of_interest{$_} } @cols;
while ( my $row = <DATA> ) {
chomp $row;
my %row; @row{@cols} = split(/,/, $row);
delete @row{@cols_to_delete};
push @{ $csv_data{ $row{dev_file} }{ "$row{test_file}:$row{diff_file}" } }, \%row;
}
}
更好的是,让我们使用正确的CSV解析器。
use Text::CSV_XS qw( );
my @cols_of_interest = qw( dev_file test_file diff_file status );
my $csv = Text::CSV_XS->new({
auto_diag => 2,
binary => 1,
});
my @cols = $csv->header(\*DATA);
my %cols_of_interest = map { $_ => 1 } @cols_of_interest;
my @cols_to_delete = grep { !$cols_of_interest{$_} } @cols;
my %csv_data;
while ( my $row = $csv->getline_hr(\*DATA) ) {
delete @$row{@cols_to_delete};
push @{ $csv_data{ $row->{dev_file} }{ "$row->{test_file}:$row->{diff_file}" } }, $row;
}