Perl - передача ссылок на подпрограмму - PullRequest
0 голосов
/ 16 ноября 2011

Я сталкиваюсь с трудностями в понимании ссылок на Perl. Вот короткий скрипт на Perl для объяснения моей проблемы [Я запустил этот код, используя perl-5.8.3]:

#!/usr/bin/perl -w
use strict;
use Data::Dumper;

my %a = ("a" => 1, "b" => 2);
my %b = ();
print Dumper(\%a, \%b);
foo(\%a, \%b);
print "+==After fn call==+\n";
print Dumper(\%a, \%b);
print "+-----------------------+\n";
bar(\%a, \%b);
print "+==After fn call==+\n";
print Dumper(\%a, \%b);

sub foo {
    my($h1, $h2) = @_;
    $h2 = $h1;
    print Dumper($h2);
}

sub bar {
    my($h1, $h2) = @_;
    %{$h2} = %{$h1};
}

Я полагаю, в обеих подпрограммах $ h1 и $ h2 - локальные переменные. Тем не менее, bar () фактически меняет значение исходного% b, а foo () - нет. Почему это так?

Ответы [ 4 ]

6 голосов
/ 16 ноября 2011
sub foo {
    my($h1, $h2) = @_;  # copy two hash references into lexicals
    $h2 = $h1;          # copy the value in lexical $h1 into $h2
                        # $h2 looses its binding to the hash ref
    print Dumper($h2);
}

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

sub bar {
    my($h1, $h2) = @_;  # copy two hash references into lexicals
    %{$h2} = %{$h1};    # the hash referred to by $h1 is unpacked into a list
                        # the hash referred to by $h2 is exposed as an lvalue
                        # the assignment operator installs the rhs list into 
                        # the lvalue, replacing any previous content
}

Так что в основном в первом примере вы имеете дело только со значениями, и применяется нормальная семантика значений. Во втором случае вы разыменовываете значения, что превращает их обратно в расширенные типы (в нашем случае это HASH).

2 голосов
/ 16 ноября 2011

$h2 - лексическая переменная, которая содержит ссылку. Изменение $h2 просто заменяет ссылку в нем.

%{$h2} - это хеш, на который ссылается $h2 (он же %b), поэтому изменение %{$h2} (он же %b) меняет хэш, на который ссылается $h2 (он же %b).

Вы, кажется, ожидаете, что изменение одной переменной ($h2) изменит другую (%b), но я не знаю, почему у вас есть такое ожидание. Это даже не один и тот же тип переменной! Как можно даже попытаться изменить элементы хэша, изменив скаляр, если у скаляра нет элементов (по крайней мере, в том же смысле, что и у хэша).

1 голос
/ 17 ноября 2011

Эрик Стром прав, но давайте посмотрим, сможем ли мы объяснить это по-другому:

sub foo {
    my($h1, $h2) = @_;
    $h2 = $h1;

}

Давайте сделаем все проще: $h1 указывает на ячейку памяти # 1 и$h2 указывает на ячейку памяти # 2.Ваше утверждение $h2 = $h1 теперь заставляет $h2 указать и на ячейку памяти # 1.

Изменилось ли содержимое ячейки памяти № 1?Нет. Изменилось ли содержимое ячейки памяти № 2?

Как только вы покидаете подпрограмму, $h1 и $h2 больше не существуют.

sub bar {
    my($h1, $h2) = @_;
    %{$h2} = %{$h1};
}

Когда вы говорите %{$h1}, вы сейчас говорите о содержимомячейка памяти № 1.В вашем задании вы копируете содержимое ячейки памяти № 1 в ячейку памяти № 2.Обратите внимание, что $h1 все еще указывает на ячейку памяти # 1, а $h2 все еще указывает на ячейку памяти # 2.Таким образом, значения $h1 и $h2 не меняются, но меняется то, на что они указывают.

Теперь давайте рассмотрим %a и %b.Содержимое %a находилось в ячейке памяти # 1, а содержимое %b находилось в ячейке памяти # 2.В sub foo мы не меняли информацию в ячейке памяти # 2, поэтому значение %b не изменилось.

В sub bar мы перепутали содержимое ячейки памяти #2, поэтому значение %b (которое хранит его содержимое в ячейке памяти № 2) изменилось.

Кстати, обратите внимание, что изменение %a после вызова подпрограммы не изменится %bсовсем.Они могут использовать одно и то же содержимое, но они не являются одной и той же переменной.

0 голосов
/ 17 ноября 2011

Это не имеет ничего общего с передачей или подпрограммами.Это только смущает проблему.Вы поймете это лучше, если рассмотрите тот же код без вызова подпрограмм:

#!/usr/bin/perl -w
use strict;
use Data::Dumper;

my %a = ("a" => 1, "b" => 2);
my %b = ();
print Dumper(\%a, \%b);
my $h1 = \%a;
my $h2 = \%b;
$h2 = $h1;
print "+==After fn call==+\n";
print Dumper(\%a, \%b);
print "+-----------------------+\n";
$h1 = \%a;
$h2 = \%b;
%{$h2} = %{$h1};
print "+==After fn call==+\n";
print Dumper(\%a, \%b);
...