Передача хеша в подпрограмму без изменения ввода - PullRequest
0 голосов
/ 23 декабря 2018

Я пытаюсь отладить какое-то странное поведение при обработке хэша в Perl.Я передаю хэш (не ref) подпрограмме и по какой-то причине он обновляет его.

some_sub($a,%{$hash});
sub some_sub {
    my ($a,%hash) = @_;
    my @struct;
    while (my ($dir, $data) = each %hash) {
        foreach my $id (keys(%{$data})) {
            my $entry = $data->{$id};
            $entry->{id} = $id;
            my $parent = $data->{$entry->{id}};
            unless ($parent) {
                push @struct, $entry
            } else {
                push @{$parent->{children}},$entry;
            }
        }
    }
}
my %h= %{$hash};
print Dumper(\%h);

Подпрограмма some_sub действительно меняет %hash, но только для внутренней области видимости, поэтому она должнане изменять данные извне %hash.Кроме того, я передаю хеш как хэш, а не как хэш.Я подозревал, что sub some_sub вставляет адреса памяти в %hash, но я не уверен.

Как мне отладить и решить эту проблему?

EDIT : Я также пытался передать ссылку на хэш в подпрограмму и разыменовать ссылку на хэш в другой хэш, выполняя все операции с новым хешем.

Ответы [ 2 ]

0 голосов
/ 23 декабря 2018

Аргументы передаются в функцию в виде плоского списка скаляров, поэтому

some_sub($a, %{$hash})

содержит ключи и значения хэша, переданные в виде списка после $a

some_sun($a, key, value, ...);

Когда эти пары ключ-значение назначаются хешу в функции, после этого вы работаете непосредственно со ссылками (ваши значения хеша), поэтому данные в вызывающей стороне изменяются.

Не указано, для чего предназначениено если вы не хотите, чтобы данные вызывающего абонента изменяли одно исправление, это избегает изменения данных в подпрограмме, возможно, путем введения локальных переменных для каждой ссылки, с которой сталкивается обработка.Если они сами могут содержать ссылки, вам все равно нужно быть очень осторожным.

Проще сделать полную глубокую копию хэша, если структура данных не велика.Например

use Storable qw(dclone);

some_sub($v, $hashref);

sub some_sub {
    my ($var, $hr) = @_;
    my $cloned_hashref = dclone($hr);
    # work away with $cloned_hashref
}
0 голосов
/ 23 декабря 2018

Каждое значение в хэше является скаляром.Если у вас есть вложенный хеш, внутренний хеш хранится как скаляр - ссылка на хеш.Поэтому при изменении вложенных структур изменения происходят в ссылочном хэше, который также ссылается на исходный хэш.

#! /usr/bin/perl
use warnings;
use strict;

sub change {
    my %hash2 = @_;
    for my $key (keys %hash2) {
        ++$_ for values $hash2{$key};
    }
}

my %hash = (a => {b => 12, c => 24});
change(%hash);
use Data::Dumper; print Dumper \%hash;

Вывод:

$VAR1 = {
          'a' => {
                   'b' => 13,
                   'c' => 25
                 }
        };

Процесс полученияструктура, которая похожа на оригинал, но содержит различные ссылки, называется клонирование или глубокое копирование .См. Клон или dclone из Хранилище .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...