我正在编写一个解析文件的脚本,并希望将整个结果放在一个数组中。我遇到了一个问题,我将其归结为以下代码:
use strict;
use warnings;
use Data::Dumper;
my @sections = ();
my @sections1 = qw/sect1 sect2 sect3/;
my @sections2 = qw/sect4 sect5/;
my @textbooks = ();
my $text1 = { title => "title1", author => "author1" };
my $text2 = { title => "title2", author => "author2" };
for ( @sections1 ) {
push(@sections, $_);
}
$text1->{sections} = \@sections;
@sections = ();
for ( @sections2 ) {
push(@sections, $_);
}
push(@textbooks, $text1);
$text2->{sections} = \@sections;
print Dumper($text2);
push(@textbooks, $text2);
print Dumper(@textbooks);
第一个打印翻斗车的结果如下:
$VAR1 = {
'title' => 'title2',
'sections' => [
'sect4',
'sect5'
],
'author' => 'author2'
}
,第二个结果是:
$VAR1 = {
'sections' => [
'sect4',
'sect5'
],
'title' => 'title1',
'author' => 'author1'
};
$VAR2 = {
'title' => 'title2',
'sections' => $VAR1->{'sections'},
'author' => 'author2'
};
我有两个问题,我确信这是相关的。
我意识到第一部分是一个参考,所以它们包含我期望的第二部分。我认为行@sections=()
将创建一个新数组,稍后将创建一个新引用。显然我没有正确地考虑这个问题。
第二节的内容是什么?从$text2
的输出看起来它是正确的,直到推送。
答案 0 :(得分:1)
\@sections
是对@sections
容器(数组)的引用。
@sections = ()
不会创建新数组,但会清空旧数组。要检查两个变量是否相同,请比较它们的引用,
use strict;
use warnings;
my @sections = 1 .. 3;
my $ref1 = \@sections;
@sections = ();
print "identical!\n" if $ref1 == \@sections;
答案 1 :(得分:1)
问题是只有一个@sections
数组,无论你对它的内容做什么,引用\@sections
都将引用相同的数组
转储器输出显示此
$VAR2 = {
'title' => 'title2',
'sections' => $VAR1->{'sections'},
'author' => 'author2'
};
表示$VAR2->{sections}
与$VAR1->{sections}
的引用相同,这显然是正确的,因为它们都是对同一@sections
数组的引用。它包含的数据只是在最新修改后留下的数据。这是@sections2
的副本,其中包含('sect4', 'sect5')
可能有帮助的一些概念
您应该尽可能将变量声明为 late ,最好是在他们的第一个使用点
您可以编写循环
for ( @sections1 ) {
push(@sections, $_);
}
只是
push @sections, @sections1
而不是
$text1->{sections} = \@sections
分配对数组@sections
的引用,您可以使用
$text1->{sections} = [ @sections ]
创建一个新的匿名数组,从@sections
的内容填充它,并返回对它的引用。这样,您就可以自由修改@sections
而无需更改已保存在$text1
你的代码可能应该写成这样的代码,但你还没有说过你想对数据做些什么,所以你可能需要做一些改变
我强烈建议您优先使用Data::Dump
Data::Dumper
。您可能需要安装它,因为它不是核心模块,但它非常值得,因为转储输出更整洁,更简洁,更易读
use strict;
use warnings;
use Data::Dump;
my @sections1 = qw/ sect1 sect2 sect3 /;
my @sections2 = qw/ sect4 sect5 /;
my @textbooks = (
{ title => 'title1', author => 'author1' },
{ title => 'title2', author => 'author2' },
);
$textbooks[0]{sections} = \@sections1;
$textbooks[1]{sections} = \@sections2;
dd \@textbooks;
<强>输出强>
[
{
author => "author1",
sections => ["sect1", "sect2", "sect3"],
title => "title1",
},
{
author => "author2",
sections => ["sect4", "sect5"],
title => "title2",
},
]
答案 2 :(得分:1)
你完全正确:
@sections = ();
NOT 创建一个新数组,它会覆盖旧数组的内容。
Data::Dumper
'隐藏'之一就是引用。
试试这个:
foreach my $key ( keys %{$text2} ) {
print $key, $text2 -> {$key},"\n"
}
和
foreach my $thing (@textbooks) {
print "TB ref $thing\n";
foreach my $key ( keys %{$thing} ) {
print "$key => ", $thing->{$key}, "\n";
}
}
从后者,你会得到类似的东西:
TB ref HASH(0x12de994)
sections => ARRAY(0x12e43b4)
author => author1
title => title1
TB ref HASH(0x12de9ac)
sections => ARRAY(0x12e43b4)
title => title2
author => author2
注意数组在这里具有相同的ID - 这是您问题的根源。您的哈希两次具有相同的引用。 (哈希数组中的父hashes
不同)
一个简单的解决方法可能是从使用@sections
切换到$sections
,因为在以下情况下:
@sections = ();
不构成“新”数据结构:
$sections = [];
因为[]
是一个匿名数组,你正在创建,只是重新分配引用。
另一种解决方案通常是使用my
缩小范围,但是使用的代码不能很好地工作 - 尽管可以很好地使用foreach
循环。