I am new to Perl, can anyone explain the following scripts for me please:

#!/usr/bin/env perl
use strict;
use warnings;
sub f1($) { my ($v) = @_; print "f1 $v\n"; }
sub f2(@) { my ($v) = @_; print "f2 $v\n"; }
my $s = "ww";
my @a = ("xx", "yy", "zz");
f1 $s; f1 @a; f2 $s; f2 @a;

The output in my computer is :

f1 ww
f1 3
f2 ww
f2 xx     # why!!

Can anyone explain why the fourth output is xx? I thought it should be zz, since when array converts to scalar, it should be the last element of array.

有帮助吗?

解决方案

No, with a statement such as:

my ($v, $foo, $bar) = @_;

$v will be assigned the first value in the @_ array, $foo the second, and so on. This is because the parentheses impose a list context. Any excess values will be ignored, unless one of your variables is an array, in which case it will slurp all remaining values.

my ($v, @foo, $bar) = @_;   # wrong! $bar will never get any value

$v will get the first value, @foo all the rest. $bar will be undefined.

You may be thinking of assignment using a list:

my $v = qw(a b c);

But this is wrong, and will cause an error:

Useless use of a constant (a) in void context at -e line 1.
Useless use of a constant (b) in void context at -e line 1.

This is because the LHS using scalar context, it will (more or less) be similar to:

'a';
'b';
my $v = 'c';

You may notice that if we impose list context by putting $v inside parentheses, we get a different result:

my ($v) = qw(a b c);  # $v is now 'a'

ETA: Regarding prototypes:

In f1, what you see is that the array is forced into scalar context because the subroutine expects a scalar argument. That is why f1 with an array prints 3 (the size). When the prototype looks for an array, the array remains in default list context, and the assignment is done as per normal (as described above).

As an extra note: prototypes have a very specific use, to make subroutines behave more like certain built-ins with regard to argument handling. Such as sort { code here } or push @array, $foo.

If this is not what you are after, you should skip prototypes all together and simply write:

sub f1 {
...
}

Documentation here

其他提示

Perl array behaves in 2 differents flavours, regarding context:
Scalar context:

my $a = @tab; # get the array length
Array context:
my @newTab = @tab; # newTab is a copy of tab
Which can be reworded like this:
# 3 scalars in an array context (see parens) gets the contents of the tab
my ($a,$b,$c) = @tab; 
Here, since @tab can be wider than the number of scalars, these scalars are populated from the beginning of the tab (and not from the end). So your code:
my ($a) = @tab;
will echo the first element of the tab

  • An array can't be converted to a scalar. An array can be evaluated in scalar context, though.

  • An array evaluated in scalar context does not return the last element of the array. As you saw with f1, it returns the number of elements in the array.

    $ perl -E'my @a = qw( xx yy zz ); say @a; say scalar(@a);'
    xxyyzz
    3
    
  • Neither array is being evaluated in scalar context. An argument list expression is evaluated in list context.

    f(@a);
    

    is the same as

    f($a[0], $a[1], $a[2]);
    

    The RHS of a list assignment in evaluated in list context.

    my ($v) = @_;
    

    is the same as

    my ($v) = ($_[0], $_[1], $_[2]);
    

    which is the same as

    my ($v, undef, undef) = ($_[0], $_[1], $_[2]);
    
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top