首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用相同的哈希,为什么在分配哈希引用后没有覆盖数据?

使用相同的哈希,为什么在分配哈希引用后没有覆盖数据?
EN

Stack Overflow用户
提问于 2013-07-31 18:01:12
回答 3查看 88关注 0票数 0

我编写了一个例程,它使用散列构建一个复杂的数据结构。

代码语言:javascript
复制
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的新副本。那么,幕后发生了什么呢?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-07-31 18:47:34

该程序的输出是:

代码语言:javascript
复制
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时,它会发生变化。

修改这一点,以便我可以有一个更紧凑的输出,并能够调用显示作为一个函数。

代码语言:javascript
复制
#!/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";
        }
    }
}

这方面的产出如下:

代码语言:javascript
复制
--- 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包含的内容?两个改变..。添加一行以显示顶部附近的内存:

代码语言:javascript
复制
my %th1 = ();
my %th2 = ();

print \%th1, "\t", \%th2,"\n";  # this line added

display改变了:

代码语言:javascript
复制
sub display {
    my $hr = shift;
    for my $key1 (keys %$hr) {
        print "$key1 --> $hr->{$key1}\n";
    }
}

现在的输出是:

代码语言:javascript
复制
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背后被更改。

很有可能,你希望在每一个地点都有不同的值。最简单的方法是创建一个匿名散列并分配:

代码语言:javascript
复制
#!/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";
        }
    }
}

其中的指纹:

代码语言:javascript
复制
--- 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

您可以看到两个单独的内存地址和两个独立的值集。

票数 2
EN

Stack Overflow用户

发布于 2013-07-31 18:45:50

你认为为什么要复制这些值?如果运行您的代码,将得到以下输出(删除空行):

代码语言:javascript
复制
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

这正是我所期望的,并表明没有进行任何复制,通过任何一个散列引用都会产生相同的结果。

票数 0
EN

Stack Overflow用户

发布于 2013-08-02 17:18:12

梅尔帕。我感谢每个人的耐心,因为我第一次重新学习Perl。我在行动中问错了问题。

我应该询问如何创建一个动态变量,这样它的引用,即对一个新哈希变量的唯一引用,就可以分配给另一个哈希变量。正如人们所评论的那样,我在OP中编写的直线代码不起作用。

以下是我最后所做的工作--我已经测试过了。不知道Perl内部,我假设每次执行该语句时都会创建一个新的动态变量:(请注意下面的代码示例是OP的示例所包含的内容。)

my %read_data = ();

每次执行$tiered_cns{$idx} = \%read_data;时,引用都是一个不同的变量。

代码语言:javascript
复制
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;
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18019278

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档