Passing arrays to functions in Perl

2020-07-02 10:20发布

问题:

I think I have misunderstood some aspects of argument passing to functions in Perl. What's the difference between func(\@array) and func(@array)?

AFAIK, in both functions, arguments are passed by reference and in both functions we can change the elements of @array in the main program. So what's the difference? When should we use which?

@array = (1,2,3);
func(@array);
func(\@array);

sub func {
    ...
}

Also, how do I imitate pass-by-value in Perl? Is using @_ the only way?

回答1:

AFAIK, in both functions, arguments are passed by reference and in both functions we can change the elements of @array in the main program.

"change the elements of", yes. However, in the func(@array) case, the sub has no means to make other changes to the array (truncating it, pushing, popping, slicing, passing a reference to something else, even undef'ing it).

I would avoid using the term "passed by reference", since the mechanism is completely different than Perl's references. It is less overloaded :) to say that in the sub, @_'s elements start off aliased to the elements passed to the sub.



回答2:

It's impossible to pass arrays to subs. Subs take a list of scalars for argument. (And that's the only thing they can return too.)

You can pass a reference to an array:

func(\@array)

You can pass the elements of an array:

func(@array)

When should we use which?

If you want to pass more than just the elements of the array (e.g. pass $x, $y and @a), it can become tricky unless you pass a reference.

If you're going to process lists (e.g. sum mysub grep { ... } ...), you might not want to pass a reference.

If you want to modify the array (as opposed to just modifying the existing elements of the array), you need to pass a reference.

It can be more efficient to pass a reference for long arrays, since creating and putting one reference on the stack is faster than creating an alias for each element of a large array. This will rarely be an issue, though.

It's usually decided by one of the first two of the above. Beyond that, it's mostly a question of personal preference.


Also, how do I imitate pass-by-value in Perl?
sub foo {
   my ($x) = @_;   # Changing $x doesn't change the argument.
   ...
}

sub foo {
   my @a = @_;   # Changing @a or its contents
   ...           #    doesn't change the arguments.
}


回答3:

func(\@array) passes a reference. func(@array) passes a list (of the elements in @array). As Keith pointed out, these elements are passed by reference. However, you can make a copy inside the sub in order to pass by value.

What you are after is this:

sub func {
    my @array = @_;
}

This will pass a copy of the arguments of func to @array, which is a local variable within the scope of the subroutine.

Documentation here