perl中的隐式转换

时间:2012-06-22 06:22:03

标签: perl implicit-conversion weak-typing

我是Perl的新手,任何人都可以为我解释以下脚本:

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

我的电脑输出是:

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

任何人都可以解释为什么第四个输出是xx?我认为它应该是zz,因为当数组转换为标量时,它应该是数组的最后一个元素。

3 个答案:

答案 0 :(得分:4)

不,声明如下:

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

$v将被分配@_数组中的第一个值,$foo第二个,依此类推。这是因为括号强加了一个列表上下文。除非您的一个变量是数组,否则任何多余的值都将被忽略,在这种情况下,它将会覆盖所有剩余的值。

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

$v将获得第一个值@foo$bar将是未定义的。

您可能正在考虑使用列表进行分配:

my $v = qw(a b c);

但这是错误的,会导致错误:

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.

这是因为LHS使用标量上下文,它将(或多或少)类似于:

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

您可能会注意到,如果我们通过将$v括在括号中来强加列表上下文,我们会得到不同的结果:

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

ETA:关于原型:

f1中,您看到的是数组被强制进入标量上下文,因为子例程需要一个标量参数。这就是为什么带有数组的f1打印3(大小)。当原型查找数组时,该数组仍保留在默认列表上下文中,并按照正常情况完成分配(如上所述)。

作为额外的注释:原型具有非常特殊的用途,使子程序在参数处理方面的行为更像某些内置函数。例如sort { code here }push @array, $foo

如果这不是您所追求的,那么您应该一起跳过原型并简单地写

sub f1 {
...
}

文档here

答案 1 :(得分:1)

Perl数组的行为有2种不同的风格,关于上下文:
标量上下文:

my $a = @tab; # get the array length
数组上下文:
my @newTab = @tab; # newTab is a copy of tab
哪个可以像这样重写:
# 3 scalars in an array context (see parens) gets the contents of the tab
my ($a,$b,$c) = @tab; 
这里,由于@tab可以比标量的数量更宽,因此这些标量从标签的开头(而不是从结尾)填充。所以你的代码:
my ($a) = @tab;
将回显标签

的第一个元素

答案 2 :(得分:0)

  • 无法将数组转换为标量。但是,可以在标量上下文中计算数组。

  • 在标量上下文中计算的数组不会返回数组的最后一个元素。正如您在f1中看到的那样,它返回数组中元素的数量。

    $ perl -E'my @a = qw( xx yy zz ); say @a; say scalar(@a);'
    xxyyzz
    3
    
  • 在标量上下文中都没有评估数组。在列表上下文中计算参数列表表达式。

    f(@a);
    

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

    列表上下文中评估的列表分配的RHS。

    my ($v) = @_;
    

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

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