简体   繁体   中英

hash copy and delete in perl

I want to back up the hash, keep the original hash, and use the backed up hash data.

And deleted the backup hash data.

However, the original hash data has been deleted.

Here is the code.

my %hash = (
    'data1' => {
        'data2' => {
            'data3' => 'one',
        },
    },
);
foreach (1..3) {
    my %hash_backup = %hash;
    print $hash{'data1'}->{'data2'}->{'data3'},"\n";
    print $hash_backup{'data1'}->{'data2'}->{'data3'},"\n";
    print "-------------------------------\n";

    delete $hash_backup{'data1'}->{'data2'};

    print $hash{'data1'}->{'data2'}->{'data3'},"\n";
    print $hash_backup{'data1'}->{'data2'}->{'data3'},"\n";
    print "================================\n";
}

Result,

one
one
-------------------------------


================================


-------------------------------


================================


-------------------------------


================================

If you change the delete code, it works normally.

delete $hash_backup{'data1'};

Result,

one
one
-------------------------------
one

================================
one
one
-------------------------------
one

================================
one
one
-------------------------------
one

================================

I think it is a hash reference problem.

How can I keep the original hash and delete the backup hash?

If you assign a reference to a new variable, the value behind the reference is not copied. Instead, the reference is copied. Imagine you have the name of a book written on a piece of paper. If you give me a copy of that paper, I do not get a copy of the book, only of the name that references the book.

You need to copy each individual reference. An easy way to do this is with dclone from the core module Storable .

use Storable 'dclone';
my %hash_backup = %{ dclone(\%hash) };

If your data structure is smaller than three levels on average, you might want to look into Clone , which claims it's faster.

use Clone 'clone';
my %hash_backup = %{ clone(\%hash) };

In both cases, a reference is expected. Because you want a hash, and not a hash reference, you need to pass in a new ref \\%foo and dereference on the way out %{ ... } .

If you wanted to do this on your own, you would have to walk the data structure, copying each reference. To force Perl to make a copy of the data, and not the reference, you need to dereference and create a new reference.

use strict;
use warnings;
use Data::Printer;

my $foo = { foo => 'bar' };
my $bar = { %$foo };
$bar->{foo} = 123;

p $foo;
p $bar;

This outputs

\ {
    foo   "bar"
}
\ {
    foo   123
}

I suggest you read perlref and perlreftut .

The thing you need to realise is the way multidimensional data structures work in perl - they work by references.

So you don't have a hash of hashes - you have a hash of hash references .

Try:

print values %hash;

Or

print $hash{data1};

And you will see something like:

HASH(0x33cff8)

Which is where the value of $hash{one} references.

What you are doing is adding that reference to your second hash. But the structure it refers to... is still the original one:

print $hash_backup{data1};

will also print:

HASH(0x33cff8)

So they're not two separate data structures - they're both referring to the same sub-hash.

As to what the solution is? Well, it depends what you're trying to accomplish. Copying a hash like that doesn't work the way you're assuming, so you need to do something else. There's a variety of methods of cloning it, such as using Storable , or just walking the keys recursively 'by hand'. But I'd suggest first considering what your goal is, and try and find something that fits.

You need a deep copy or clone to copy the entirely hash and not only the first level of elements.

See here:

What's the best way to deep copy a hash of hashes in Perl?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM