perl 中的隐式转换

Posted

技术标签:

【中文标题】perl 中的隐式转换【英文标题】:implicit-conversion in perl 【发布时间】:2012-06-24 10:47:04 【问题描述】:

我是 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,因为当数组转换为标量时,它应该是数组的最后一个元素。

【问题讨论】:

+1 提问。从未尝试过sub f1($)sub f2(@) 语法。 @Devendra,你不应该这样做。 @cjm- 没错。但是问题指出了一些有趣的事情。这也是我们使用use strict; use warnings;的时候 这里有一些 link 用于不寻常的 shebang 行 #!/usr/bin/env perl @Devendra,并非所有人都觉得 shebang 线不寻常。 :) 【参考方案1】:

不,用如下语句:

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

【讨论】:

【参考方案2】:

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;
将回显选项卡的第一个元素

【讨论】:

【参考方案3】:

数组无法转换为标量。不过,数组可以在标量上下文中求值。

在标量上下文中计算的数组不返回数组的最后一个元素。正如您在 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]);

【讨论】:

以上是关于perl 中的隐式转换的主要内容,如果未能解决你的问题,请参考以下文章

追踪 Python 2 中的隐式 unicode 转换

Scala中的隐式转换|理解

Mysql中的隐式转换

Java 中的隐式转换是如何工作的?

Java 中的隐式转换是如何工作的?

避免构造函数中的隐式转换。 'explicit' 关键字在这里没有帮助