If perl is call-by-reference why does this happen?

2019-08-25 08:02发布

I've read that perl uses call-by-reference when executing subrutines. I made a simple piece of code to check this property, but it behaves like if perl was 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";

This produces the following output:

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

If arguments were treated in a call-by-reference way, shouldn't x be equal to x1 and y equal to y1?

3条回答
Fickle 薄情
2楼-- · 2019-08-25 08:15

I'm just starting with Perl as well, and I believe you're misunderstanding just what you're passing to the subroutine. When you pass $x and $y you are passing the scalars $x and $y are set to. You need to explicitly pass a reference, which also happens to be a scalar (being the only thing are ever allowed to pass to subroutines). I understand where you're coming from in thinking things are call-by-reference since for arrays and hashes, since you need to pass references to those.

This code should do what you're looking for:

#!/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";

I pass in references to $x and $y using \$x and \$y. Then, I use $$x and $$y to dereference them within the subroutine.

查看更多
放我归山
3楼-- · 2019-08-25 08:27

Perl is always definitely call by reference. You're statement ($x1, $y1) = @_ is copying the original argument values, since @_ holds aliases to the original parameters.

From perlsub manpage:

Any arguments passed in show up in the array @_ . Therefore, if you called a function with two arguments, those would be stored in $[0] and $[1] . The array @_ is a local array, but its elements are aliases for the actual scalar parameters. In particular, if an element $_[0] is updated, the corresponding argument is updated (or an error occurs if it is not updatable).

查看更多
在下西门庆
4楼-- · 2019-08-25 08:36

To modify the values outside of the sub, you would have to modify the values of @_.

The following sub interchange does modify the values:

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";
}

This gives the output:

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

More info here: http://www.cs.cf.ac.uk/Dave/PERL/node51.html

But, to quote the article:

You can see that the function was able to affect the @array variable in the main program. Generally, this is considered bad programming practice because it does not isolate what the function does from the rest of the program.

查看更多
登录 后发表回答