我编写了一个使用哈希构建复杂数据结构的例程。
use strict;
my %th1 = ();
my %th2 = ();
my $idx = 0;
$th2{"suffix"} = "A";
$th2{"status"} = 0;
$th2{"consumption"} = 42;
$th1{$idx} = \%th2;
$idx++;
$th2{"suffix"} = "B";
$th2{"status"} = 0;
$th2{"consumption"} = 105;
$th1{$idx} = \%th2;
for my $key1 (keys %th1)
{
for my $key2 (keys %{$th1{$key1}})
{
print "Key1=$key1, Key2=$key2, value=" . $th1{$key1}->{$key2} . "\n\n";
}
}
我的问题是,当分配哈希引用时,为什么$idx == 0
的第一组数据不会被破坏?
分配哈希引用时是否创建了副本$th1{$idx} = \%th2;
?
执行此行时
$th2{"suffix"} = "B";
为什么$th1{0}
的哈希值没有损坏?
值没有被破坏,但我很好奇保留这些值的机制。代码未明确创建%th2
的新副本。那么,幕后发生了什么?
答案 0 :(得分:2)
该程序的输出是:
Key1=1, Key2=status, value=0
Key1=1, Key2=suffix, value=B
Key1=1, Key2=consumption, value=105
Key1=0, Key2=status, value=0
Key1=0, Key2=suffix, value=B
Key1=0, Key2=consumption, value=105
如果您在运行时看到不同的内容,请说明您所看到的内容。
没有腐败,也没有复制。 %th1
包含指向其他哈希的指针。
一个内存位置有一个哈希值,另一个哈希值另一个哈希值。在您修改%th2
时,它会发生变化。
稍微修改一下,以便我可以拥有更紧凑的输出,并能够将显示调用为函数。
#!/usr/bin/perl
my %th1 = ();
my %th2 = ();
$th2{"suffix"} = "A";
$th2{"status"} = 0;
$th2{"consumption"} = 42;
$th1{0} = \%th2;
print "--- After first block:\n";
display(\%th1);
$th2{"suffix"} = "B";
print "--- Modified th2 suffix to B:\n";
display(\%th1);
$th2{"status"} = 0;
$th2{"consumption"} = 105;
print "--- finished modification of th2:\n";
display(\%th1);
$th1{1} = \%th2;
print "--- after assignment to th1{1} :\n";
display(\%th1);
exit;
sub display {
my $hr = shift;
for my $key1 (keys %$hr) {
print "$key1:\n";
for my $key2 (keys %{$hr->{$key1}}) {
print "\t$key2 = $hr->{$key1}{$key2}\n";
}
}
}
这个输出是:
--- After first block:
0:
status = 0
suffix = A
consumption = 42
--- Modified th2 suffix to B:
0:
status = 0
suffix = B
consumption = 42
--- finished modification of th2:
0:
status = 0
suffix = B
consumption = 105
--- after assignment to th1{1} :
1:
status = 0
suffix = B
consumption = 105
0:
status = 0
suffix = B
consumption = 105
您可以看到%th2
的修改在%th1
中的解除引用值中生效。
让我们以不同的方式看待它...而不是打印出值,让我们打印出%th1
包含的内容?两个变化......添加了显示内存附近的行:
my %th1 = ();
my %th2 = ();
print \%th1, "\t", \%th2,"\n"; # this line added
和display
已更改:
sub display {
my $hr = shift;
for my $key1 (keys %$hr) {
print "$key1 --> $hr->{$key1}\n";
}
}
现在输出是:
HASH(0x239edb0) HASH(0x239edf8)
--- After first block:
0 --> HASH(0x239edf8)
--- Modified th2 suffix to B:
0 --> HASH(0x239edf8)
--- finished modification of th2:
0 --> HASH(0x239edf8)
--- after assignment to th1{1} :
1 --> HASH(0x239edf8)
0 --> HASH(0x239edf8)
%th1
的值一直指向单个哈希值。没有副本,只有一个哈希在%th1
的后面更改。
有可能,您希望每个点都有单独的值。通过创建匿名哈希并分配:
,可以轻松完成此操作#!/usr/bin/perl
my %th1 = ();
my %th2 = ();
$th1{0} = {"suffix" => "A", "status" => 0, "consumption" => 42 };
print "--- After first block:\n";
display(\%th1);
$th1{1} = {"suffix" => "B", "status" => 0, "consumption" => 105 };
print "--- after assignment to th1{1} :\n";
display(\%th1);
exit;
sub display {
my $hr = shift;
for my $key1 (keys %$hr) {
print "$key1: $hr->{$key1}\n";
for my $key2 (keys %{$hr->{$key1}}) {
print "\t$key2 = $hr->{$key1}{$key2}\n";
}
}
}
打印哪些:
--- After first block:
0: HASH(0xcf6998)
status = 0
suffix = A
consumption = 42
--- after assignment to th1{1} :
1: HASH(0xd143c0)
status = 0
suffix = B
consumption = 105
0: HASH(0xcf6998)
status = 0
suffix = A
consumption = 42
您可以看到两个独立的内存地址和两组不同的值。
答案 1 :(得分:0)
为什么你认为价值被复制?如果我运行你的代码,我得到了 以下输出(删除空行):
Key1=1, Key2=status, value=0
Key1=1, Key2=suffix, value=B
Key1=1, Key2=consumption, value=105
Key1=0, Key2=status, value=0
Key1=0, Key2=suffix, value=B
Key1=0, Key2=consumption, value=105
这正是我所期待的,并表明没有正在进行复制 通过任一哈希引用产生相同的结果。
答案 2 :(得分:0)
Mea Culpa。我很感激每个人的耐心,因为我第一次重新学习Perl。我在OP中提出了错误的问题。
我应该问一下如何创建动态变量,因此可以将其引用(对新哈希变量的唯一引用)分配给另一个哈希变量。我在OP中写的直线代码将无效,正如人们所评论的那样。
以下 - 我已经测试和工作 - 是我最后做的事情。不知道Perl内部,我假设每次执行此语句时都会创建一个新的动态变量:(请注意下面的代码示例是OP的样本所进入的。)
my %read_data = ();
每次执行$tiered_cns{$idx} = \%read_data;
时,引用都是另一个变量。
sub ws_get_cons_from_latest_read
# $PkNam Package name. We disregard it.
# $DBHdl -- ICS database handle.
# $acct_no -- water acct number (integer)
# $time_stamp -- usually this value is today's date as a year to second
{
# Grab input parameters.
my ($PkNam, $DBHdl, $acct_no, $time_stamp) = @_;
# Declare local variables.
my $ptSelHdl = undef;
my $ptMtrRecRef = undef;
my $ptWsMtrReadRecRef = undef;
my $consumption = 0;
my $statement = "";
my %tiered_cns = ();
my $idx = undef;
die("wgbl_get_cons_from_latest_read passed undef handles.")
if(!defined($DBHdl) || !defined($acct_no));
$statement = "select m.* ".
"from meter m ".
"where m.acct_no = ".$acct_no;
$ptSelHdl = $DBHdl->prepare($statement);
if(!$ptSelHdl || !$ptSelHdl->execute)
{
die("Could not prepare select suffix numdigits from meter statement.");
}
$ptMtrRecRef = $ptSelHdl->fetchrow_hashref;
$idx = 0;
if(!defined($ptMtrRecRef))
{
my %read_data = ();
$read_data{"status"} = MISSING_METER_REC;
$read_data{"suffix"} = " ";
$read_data{"consumption"} = 0;
$tiered_cns{$idx} = \%read_data;
}
else
{
do
{
my %read_data = ();
$ptWsMtrReadRecRef = MtrGblFunc->mgbl_get_latest_ws_mtr_rec($DBHdl,
$ptMtrRecRef->{"acct_no"},
$ptMtrRecRef->{"suffix"});
if(!$ptWsMtrReadRecRef)
{
$read_data{"status"} = MISSING_LATEST_READ;
$read_data{"suffix"} = $ptMtrRecRef->{"suffix"};
$read_data{"consumption"} = 0;
}
else
{
$consumption = WsGblFunc->wgbl_calc_mtr_cons( $DBHdl,
$acct_no,
$ptMtrRecRef->{"suffix"},
$ptWsMtrReadRecRef->{"counter"},
$ptWsMtrReadRecRef->{"reading"},
$ptWsMtrReadRecRef->{"date_read"},
$time_stamp);
$read_data{"status"} = SUCCESS;
$read_data{"suffix"} = $ptMtrRecRef->{"suffix"};
$read_data{"consumption"} = $consumption;
$tiered_cns{$idx} = \%read_data;
$idx++;
$ptMtrRecRef = $ptSelHdl->fetchrow_hashref;
}
} until !defined($ptMtrRecRef) || !defined($ptWsMtrReadRecRef);
}
return \%tiered_cns;
}