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

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

$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?

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 в основной программе. Как правило, это считается плохой практикой программирования, потому что она не изолирует то, что функция делает от остальной части программы.

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

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

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

Я только начинаю с 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, чтобы разыменовать их в подпрограмме.

Другие вопросы по тегам