разыменование хеша без создания локальной копии - PullRequest
3 голосов
/ 04 июня 2010

В коде ниже строки 9 создается локальная копия хэша. Любые изменения в% d не приведут к изменениям глобальной переменной% h (строка: 5). Я должен использовать ссылку (строка: 8), чтобы внести изменения в% h.

Есть ли способ разыменования хеша в сабвуфере без создания локальной копии? Я спрашиваю, поскольку у меня сложная запись со многими ссылками, и навигация по ней с разыменованием будет намного проще.

  1 #!/usr/bin/perl -w
  2 use strict;
  3 use warnings;
  4 
  5 my %h;
  6 sub a {
  7 
  8     my $href = shift;
  9     my(%d) = %{$href};   # this will make a copy of global %h
 10     
 11     $$href{1}=2;     # this will make a change in global %h
 12     $d{2}=2;         # this will not a change in global %h
 13 }   
 14 a(\%h);
 15 print scalar (keys %h) . "\n";

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

Спасибо за ответы.

Вопрос в том, можно ли создать какой-то псевдоним / связывание% h в подпрограмме. Я хотел бы изменить контекст% h в подпрограмме с% d. Всякий раз, когда я создаю% d, он делает локальную копию% h - есть ли способ избежать этого или мне нужно использовать ссылки постоянно?

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

Еще раз :) Я знаю, как работает $ href. Я читаю учебные пособия / руководства / документы и т. Д. Я не нашел там ответа - я предполагаю, что это невозможно, так как там не было написано, но кто знает.

Я хочу добиться такого поведения:

  6 sub a {
  7     $h{"1"}=2;
  8 }

Что эквивалентно этому:

  6 sub a {
  8      my $href = shift;
  11     $$href{1}=2;     # this will make a change in global %h
  11     $href->{1}=2;    # this will make a change in global %h

Теперь, как это сделать с помощью% d - возможно ли это на самом деле?

6 sub a {
7        my %d = XXXXXXXXX
.. }

Что я должен поместить в XXXXXXXXX, чтобы указать% h без создания локальной копии?

Ответы [ 4 ]

6 голосов
/ 04 июня 2010

Чтобы создать локальный псевдоним значения, вам нужно использовать переменные пакета Perl, которые можно использовать с помощью синтаксиса typeglob (и local для определения псевдонима):

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

my %h;

sub a {
    my $href = shift;

    our %alias; # create the package variable (for strict)

    local *alias = $href;
        # here we tell perl to install the hashref into the typeglob 'alias'
        # perl will automatically put the hashref into the HASH slot of
        # the glob which makes %alias refer to the passed in hash.
        # local is used to limit the change to the current dynamic scope.
        # effectively it is doing:  *{alias}{HASH} = $href

    $$href{1}=2;     # this will make a change in global %h
    $alias{2}=2;     # this will also make a change in global %h
}
a(\%h);
print scalar (keys %h) . "\n";  # prints 2

Этодовольно продвинутый метод, поэтому обязательно прочитайте документы Perl на local и typeglobs, чтобы вы точно понимали, что происходит (в частности, любые подпрограммы, вызываемые из подпрограммы a после local, также будутимеет %alias в области видимости, так как local обозначает динамическую область действия. Локализация закончится, когда a вернется.)

Если вы можете установить Data::Alias или один из других модулей псевдонимов из CPAN Вы можете избежать переменной пакета и создать лексический псевдоним.Вышеуказанный метод является единственным способом сделать это без дополнительных модулей.

2 голосов
/ 04 июня 2010

Два способа использования ссылки на хеш:

  1. Тот, который вы сами использовали

    $$href{'key2'} = "key2";
    
  2. Указано выше:

    $href->{'key1'} = "key1";
    

http://perldoc.perl.org/perlreftut.html

1 голос
/ 04 июня 2010

Помогает ли это вам

$href->{1} = 2;
print scalars (keys %{$href});

0 голосов
/ 04 июня 2010

Следующий код показывает, как разыменовать, используя оператор стрелки (и да, без создания локальной переменной)

Прочитайте это для учебника по разыменованию и различным возможным разыменованиям.

use warnings;
use Data::Dumper::Simple;

my %h;
sub a {
    my $href = shift;

    #dereference using the arrow operator - *preferred*
    $href->{name} = "John"; 

}

a(\%h); #Passing the reference of the hash
print Dumper(%h);

Зачем вам нужно передавать глобальный хеш в качестве аргумента подпрограмме?

  1. Избегайте использования глобальных переменных.
  2. Предпочтительно, не меняйте состояние любых переменных после того, как они были назначены.
...