как передать переменную, список, хэш в функцию в качестве ссылки и получить обратно изменения в вызывающей программе без возврата - PullRequest
1 голос
/ 07 мая 2019

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

Этот код не выполняет работу.

sub foo{
    my $one = {$_[0]};   
    my @list = @{$_[1]};
    my %hash = %{$_[2]};
    print("\n inside foo: ${one}\n");
    print("\n inside foo: $one @list $hash{'key'}\n");
    $one = 2;
    @list = (4,5,6);
    my %hash2;
    $hash2{'key'} = 'valueModified';    
    %hash = %hash2;
    print("\n inside foo after Mod: $one\n");
    print("\n inside foo after Mod: $one @list $hash{'key'}\n");
}

my $one = 1;
my @list = (1,2,3);
my %hash;
$hash{'key'} = 'value';
my @allLocalArgs = (\$one,\@list,\%hash);
foo(\@allLocalArgs);
print("\nafter foo modification: $one @list $hash{'key'}\n");

Выход:

 inside foo: HASH(0x234a240)

 inside foo: HASH(0x234a240)  

 inside foo after Mod: 2

 inside foo after Mod: 2 4 5 6 valueModified

after foo modification: 1 1 2 3 value

Спасибо.

1 Ответ

6 голосов
/ 07 мая 2019

В принципе, и практически на любом языке вы хотите передавать объекты, которые ссылаются на структуры данных, в вызывающей программе, указателях или ссылках. В Perl это будет ссылка - и вы это делаете.

Но затем в подпрограмме вы создаете локальные копии; $one, @list и %hash в подпункте являются лексическими переменными локально для sub sub , маскируя / скрывая те, что в вызывающей области. Изменения в тех, которые не делают ничего вне области действия суб.

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

sub foo { 

    my ($rscalar, $rary, $rhash) = @_;

    $$rscalar = 2;

    @$rary = (4,5,6);

    $rhash->{'key'} = 'valueModified'; 
}

foo(\$one, \@list, \%hash);

Теперь $one, @list и %hash в вызывающем коде изменены. Подробнее о работе со ссылками см. Учебник perlreftut и справку perlref .

Обратите внимание, что foo(\@allLocalArgs); передает ссылку на массив с аргументами, поэтому подпрограмма получает один элемент - ссылку на этот массив. Вы можете сделать это, но по вопросу вопроса это не нужно, поэтому я удалил его и передал список аргументов напрямую.

Еще одна вещь, на которую следует обратить внимание, это то, что аргументы имеют псевдонимы в @_ - поэтому, если в подпрограмме вы работаете с @_ напрямую, вы меняете данные в вызывающей стороне. Таким образом, если вы передадите скалярную переменную как foo($one), тогда $_[0] = 2 в подстановке изменится $one в вызывающей стороне. Это в принципе лучше всего избегать, по моему мнению; если данные вызывающего абонента должны быть изменены, это должно быть сделано как можно более явным; передать ссылку.


Примечание по терминологии

A list в Perl - неуловимая, эфемерная структура, используемая для перемещения данных в программе; Подумайте о куче скаляров (значений) в стеке, которые собираются использовать, и они исчезнут. Возможно, передать аргументы функции (foo($v1, $v2)), или сформировать строку (join '', $v1, $v2), или создать анонимную ссылку на массив ([$v1, $v2]) и т. Д.

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

Много было написано об этом; Вот несколько ссылок, которые можно легко найти: Эффективная статья Perler (со ссылками на несколько других статей) и страница Stackoverflow Массив Perl против списка .

Короче говоря, вы спрашиваете о "скаляре, массиве, хэше".

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