列出上下文和Perl中的逗号操作符



对于"在列表上下文中求值"的含义有一些明显的混淆,特别是与逗号操作符有关。在链接的perlop文档中,它说:在列表上下文中,它只是列表参数分隔符,并将其两个参数插入列表中。但是,代码

@y = 9, 8, 7, 6;
say @y, ', ', scalar @y;

给出输出9, 1。这尊重这样一个事实,即当用作标量值(?)上的二进制操作符时,逗号操作符,的优先级低于赋值操作符=。但是,由于我分配给列表@y,分配的右侧不应该在列表上下文中进行评估,并且通过上面的引用,将逗号简单地视为分隔符吗?

我怀疑我只是没有真正理解它在列表上下文中"计算"什么;意味着,精确…

这个问题与上下文无关。[1]这是一个优先级问题。

赋值比逗号优先级高,所以

my @y = 9, 8, 7, 6;

( my @y = 9 ), 8, 7, 6;

但是你想

my @y = ( 9, 8, 7, 6 );

注意父级除了覆盖优先级之外什么都不做。

警告会捕捉到这个。始终使用use strict; use warnings;或等效的!


我怀疑我只是没有真正理解它在列表上下文中"评估"什么;意味着,精确…

每个操作符根据其计算的上下文决定执行什么和返回什么。

但是,它不会改变代码的解析方式。

左边的
  1. my @y足以导致使用列表赋值,因此足以导致在列表上下文中计算RHS。参见标量与列表赋值操作符。

如果您像您应该的那样打开警告,perl会给您一些提示,告诉您发生了什么:

#!/usr/bin/env perl
use warnings;
use strict;
use feature qw/say/;
my @y = 9, 8, 7, 6;
say @y, ', ', scalar @y;

运行显示

Useless use of a constant (8) in void context at foo.pl line 6.
Useless use of a constant (7) in void context at foo.pl line 6.
Useless use of a constant (6) in void context at foo.pl line 6.
9, 1

@y = 9, 8, 7, 6是标量上下文中逗号操作符的一个示例,并且如您所注意到的,是优先规则。它被解析为用逗号分隔的四个不同的子表达式:首先@y = 9将一个单元素列表分配给@y,然后是表达式8,7和6,所有这些都不做任何事情并生成警告,如果有任何可返回的内容,则整个过程将返回6。如果你想给变量赋值一个列表,这个列表需要放在括号里:

my @y = (9, 8, 7, 6); # Or qw/9 8 7 6/ etc.

…赋值的右边不应该在list上下文中求值吗…

只是要强调这一点:是的,它应该而且它是——在优先级规则首先应用之后。

perl -wE'my @ary = localtime, qw(a b); say for @ary'

它打印Useless use of a constant...的两个警告(ab),然后是localtime在列表上下文中运行时返回的值(而不是时间戳字符串,它在标量上下文中所做的)。

赋值的LHS处的数组实际上是强制列表上下文[1],但是由于优先级的关系,逗号不是RHS的一部分。这就是为什么在@y = 9, 8, 7, 6;中,逗号实际上是在void上下文中。Ikegami和其他人已经解释了这一点。

但是回答你的主要问题:

我怀疑我只是没有真正理解它在列表上下文中"计算"什么;意味着,精确…

是的,我不得不承认这有点令人困惑。

为了更好地理解,这里有一个示例,您可以看到Perl中三个主要上下文对逗号分隔的文本列表的影响。

use strict;
use warnings;
use Carp;

sub ctxt {
my $wa = wantarray // 2;
carp (("SCALAR","LIST","VOID")[$wa]);
}

sub commas {
return "A","B","C","D"
}
my @arr;
# --- List context
@arr = ctxt();
@arr = commas();
warn "<@arr>";
# --- Scalar context
@arr = scalar ctxt();
@arr = scalar commas();
warn "<@arr>";
# --- Void context
ctxt();
commas();
LIST at d:/Perl/pm/context.pl line 8.
main::ctxt() called at d:/Perl/pm/context.pl line 19
<A B C D> at d:/Perl/pm/context.pl line 21.
SCALAR at d:/Perl/pm/context.pl line 8.
main::ctxt() called at d:/Perl/pm/context.pl line 24
<D> at d:/Perl/pm/context.pl line 26.
VOID at d:/Perl/pm/context.pl line 8.
main::ctxt() called at d:/Perl/pm/context.pl line 29

调用者上下文传播到子例程的返回,这就是为什么在LIST -context中看到完整的LIST,而在使用标量逗号操作符时只看到最后一个元素。

ctext()只是我破解的一个辅助函数,您可以使用它来查找将来要处理的上下文。

HTH !:)


  1. 它实际上编译成一个列表赋值操作符

最新更新