Если Perl вызывается по ссылке, почему это происходит?

Я читал, что Perl использует вызов по ссылке при выполнении подпрограмм. Я сделал простой фрагмент кода для проверки этого свойства, но он ведет себя так, как если бы perl вызывался по значению:

$x=50;
$y=70;

sub interchange {
    ($x1, $y1) = @_;

    $z1 = $x1;
    $x1 = $y1;
    $y1 = $z1;

    print "x1:$x1 y1:$y1\n";
}

&interchange ($x, $y);

print "x:$x y:$y\n";

Это дает следующий результат:

$ perl example.pl
x1:70 y1:50
x:50 y:70

Если бы аргументы обрабатывались методом вызова по ссылке, разве x не должен был бы равняться x1, а y равняться y1?


person Marco Lavagnino    schedule 05.06.2014    source источник
comment
Используйте strict, используйте предупреждения, ознакомьтесь с переменные с лексической областью действия, и не вызывайте подпрограммы с ведущим &, если только вы знаете, почему вы хотите это сделать и должны это сделать. Чем раньше вы это сделаете, тем счастливее вы будете. :)   -  person pilcrow    schedule 05.06.2014
comment
Кроме того, существуют более простые способы замены значений.   -  person pilcrow    schedule 05.06.2014


Ответы (3)


Чтобы изменить значения вне подпрограммы, вам придется изменить значения @_.

Следующий sub interchange изменяет значения:

sub interchange {
    ($x1, $y1) = @_; # this line copies the values to 2 new variables

    $z1 = $x1;
    $x1 = $y1;
    $y1 = $z1;

    $_[0] = $x1; # this line added to change value outside sub
    $_[1] = $y1; # this line added to change value outside sub

    print "x1:$x1 y1:$y1\n";
}

Это дает результат:

x1:70 y1:50
x:70 y:50

Подробнее здесь: http://www.cs.cf.ac.uk/Dave/PERL/node51.html

Но, цитируя статью:

Вы можете видеть, что функция смогла повлиять на переменную @array в основной программе. Как правило, это считается плохой практикой программирования, поскольку не изолирует то, что делает функция, от остальной части программы.

person AntonH    schedule 05.06.2014
comment
@Borodin Я пытаюсь очень немного изменить исходный код ОП. Но хороший, лаконичный код :) - person AntonH; 05.06.2014

Perl всегда однозначно вызывается по ссылке. Ваш оператор ($x1, $y1) = @_ копирует исходные значения аргументов, поскольку @_ содержит псевдонимы исходных параметров.

Из man-страницы perlsub:

Любые переданные аргументы отображаются в массиве @_ . Поэтому, если вы вызвали функцию с двумя аргументами, они будут сохранены в $[0] и $[1] . Массив @_ является локальным массивом, но его элементы являются псевдонимами реальных скалярных параметров. В частности, если элемент $_[0] обновляется, соответствующий аргумент обновляется (или возникает ошибка, если он не обновляется).

person marlowe    schedule 05.06.2014

Я тоже только начинаю работать с Perl, и я полагаю, что вы неправильно понимаете, что именно вы передаете подпрограмме. Когда вы передаете $x и $y, вы передаете скаляры $x и $y. Вам нужно явно передать ссылку, которая также является скаляром (это единственное, что когда-либо разрешено передавать подпрограммам). Я понимаю, почему вы думаете, что вещи вызываются по ссылке, так как для массивов и хэшей вам нужно передавать ссылки на них.

Этот код должен делать то, что вы ищете:

#!/usr/bin/perl

$x=50;
$y=70;

sub interchange {
    ($x1, $y1) = @_;

    $z1 = $$x1; # Dereferencing $x1
    $$x1 = $$y1; # Dereferencing $x1 and $y1
    $$y1 = $z1; # Dereferencing $y1

    print "x1:$$x1 y1:$$y1\n";
}

&interchange (\$x, \$y); # Passing references to $x and $y, not their values

print "x:$x y:$y\n";

Я передаю ссылки на $x и $y, используя \$x и \$y. Затем я использую $$x и $$y для их разыменования внутри подпрограммы.

person DDP    schedule 05.06.2014