31

我试图理解 Perl 上下文,但我绊倒了一块石头;

给定代码;

#!/usr/bin/perl

my $b = (33,22,11);
print "$b\n";

my $b = () = (33,22,11);
print "$b\n";

my @b = (33,22,11);
print "@b\n";

my @b = () = (33,22,11);
print "@b\n";

结果是(最后一行是空白);

 11  

 3 

 33 22 11

 <>

由于第二次打印返回列表的长度,我假设在某个地方生成了一个数组,因为标量上下文中的数组计算为其长度。但第 4 版似乎与该假设不符。我期待看到'33 22 11'打印,但什么也没得到。这里发生了什么事?

4

3 回答 3

17

您感到困惑是因为您认为=是单个运算符,而它可能导致两个不同的运算符:列表赋值运算符或标量赋值运算符。迷你教程:标量与列表赋值运算符解释了差异。

my $b = (33,22,11);
------------------            Scalar assign in void context.
        ----------            List literal in scalar context. Returns last.

my @b = (33,22,11);
------------------            List assign in void context.
        ----------            List literal in list context. Returns all.

my $b = ( () = (33,22,11) );
---------------------------   Scalar assign in void context.
        -------------------   List assign in scalar context. Returns count of RHS
               ----------     List literal in list context. Returns all.

my @b = ( () = (33,22,11) );
---------------------------   List assign in void context.
        -------------------   List assign in list context. Returns LHS.
               ----------     List literal in list context. Returns all.

至于你的标题,强制列表上下文是不可能的。如果函数在需要标量时返回列表,则会在堆栈上产生额外的值,从而导致运算符获取错误的参数。

但是,您可以执行以下操作:

( EXPR )[0]

或者

( EXPR )[-1]

EXPR将在列表上下文中调用,但整体将仅返回返回列表的一个元素。

于 2013-06-17T00:48:15.393 回答
7

标量上下文中的列表赋值返回右侧元素的数量(案例 2)。案例 4 先赋值(33, 22, 11)(),再赋值给()(其值没有改变)@b

于 2013-06-16T18:24:48.057 回答
3

回答标题中隐含的问题:

Perl 提供了一个scalar内置函数来强制标量上下文,否则它不会被使用;类似的list内置函数不存在,我想主要是因为它可能意味着许多不同的东西,例如:

list { code to execute in list context };

可能被定义为:

sub list (&) { scalar( () = $_[0]->() ) } # return count of elements
sub list (&) { ( $_[0]->() )[0] } # return first element
sub list (&) { ( $_[0]->() )[-1] } # return last element
sub list (&) { for( $_[0]->() ) {} } # return nothing

回答问题的主体:

当被上下文混淆时,请记住运算符将上下文强加于操作数,而不是相反。在您的问题案例中,您有一个标量分配,将列表分配的结果分配给标量,这将列表分配置于标量上下文中。要知道会发生什么,只需查看列表分配将在标量上下文中返回的内容。(通常,运算符会返回最常见的含义,这意味着没有适用于所有运算符的易于记忆的规则。)

于 2013-06-16T20:26:19.847 回答