我编写了一个例程,它使用散列构建一个复杂的数据结构。
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的新副本。那么,幕后发生了什么呢?
发布于 2013-07-31 18:47:34
该程序的输出是:
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 addeddisplay改变了:
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您可以看到两个单独的内存地址和两个独立的值集。
发布于 2013-07-31 18:45:50
你认为为什么要复制这些值?如果运行您的代码,将得到以下输出(删除空行):
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这正是我所期望的,并表明没有进行任何复制,通过任何一个散列引用都会产生相同的结果。
发布于 2013-08-02 17:18:12
梅尔帕。我感谢每个人的耐心,因为我第一次重新学习Perl。我在行动中问错了问题。
我应该询问如何创建一个动态变量,这样它的引用,即对一个新哈希变量的唯一引用,就可以分配给另一个哈希变量。正如人们所评论的那样,我在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;
}https://stackoverflow.com/questions/18019278
复制相似问题