如何判断Perl代码中的一组括号是作为分组括号还是形成列表?

7
在Perl中,括号用于覆盖优先级(与大多数编程语言相同),也用于创建列表。如何确定特定的一对括号将被视为分组结构还是一个元素的列表?
例如,我非常确定这是一个标量而不是一个单元素列表:(1 + 1)。 但是对于更复杂的表达式呢?有没有简单的方法来判断?

我想我最担心的是意外地将包含结果的一个元素列表分配给标量,而不是结果本身。但如果我正确阅读回复,这实际上是不可能的,除非我做类似于$x = @{[ 1 + 1 ]};的事情。似乎将列表分配给标量与将数组分配给标量是不同的。如果您将包含数组的列表分配给标量会发生什么?$x = (@list); - Ryan C. Thompson
在一个赋值语句中,左边确定了右边将被评估的上下文环境。因此,当你将一个数组分配给一个标量变量时,该数组将会在标量上下文中进行评估。在标量上下文中评估的数组返回数组中项目的数量。你评论中两个示例都属于这种情况。还要注意,这里我们谈论的是在标量上下文中对数组的评估,而不是在标量上下文中对列表的评估,因为在标量上下文中不存在列表。 - FMc
我想我一直认为列表和数组基本上是等价的和可互换的,但它们并不是。 - Ryan C. Thompson
2个回答

18

这里有三个重要原则:

上下文至关重要。 对于你的示例 (1 + 1) 的评估取决于上下文。

$x = (1 + 1); # Scalar context. $x will equal 2. Parentheses do nothing here.
@y = (1 + 1); # List context. @y will contain one element: (2).
              # Parens do nothing (see below), aside from following 
              # syntax conventions.
在标量上下文中,没有列表这样的东西。要了解这一点,请尝试将“看起来像列表”的内容分配给标量变量。思考这个问题的方法是专注于逗号运算符的行为方面:在标量上下文中,它评估其左参数,将该值丢弃,然后评估其右参数并返回该值。在列表上下文中,逗号运算符将两个参数插入列表中。
@arr  = (12, 34, 56); # Right side returns a list.

$x    = (12, 34, 56); # Right side returns 56. Also, we get warnings
                      # about 12 and 34 being used in void context.

$x = (@arr, 7);       # Right side returns 7. And we get a warning
                      # about using an array in a void context.

括号不会创建列表,逗号操作符(如果我们处于列表上下文中)才会创建列表。在 Perl 代码中输入列表时,括号是出于优先级的原因而需要使用的——而非用于创建列表的原因。以下是一些示例:

  • 括号没有任何效果:我们正在标量上下文中评估一个数组,因此右侧返回的是数组大小。

  • $x = (@arr);
    
  • 不需要使用括号来创建只有一个元素的列表。

  • @arr = 33;         # Works fine, with @arr equal to (33).
    
    但是在多个项目时需要括号——出于优先级的原因。
    @arr = 12, 34, 56; # @arr equals (12). And we get warnings about using
                       # 34 and 56 in void context.
    

8
  1. 上下文。
  2. 括号在创建列表时没有你想象中的作用。

例如:

$x = 1 + 1;   # $x is 2.
$x = (1 + 1); # $x is 2.
@x = 1 + 1;   # @x is (2).
@x = (1 + 1); # @x is (2).

$x = (1 + 1, 1 + 2); # $x is 3.
@x = (1 + 1, 1 + 2); # @x is (2, 3).

粗略地说,在列表上下文中,逗号运算符分隔列表项;在标量上下文中,逗号运算符是C语言的“串联逗号”,它评估其左侧和右侧,并返回右侧的值。在标量上下文中,括号组合表达式以覆盖操作顺序,在列表上下文中,括号实际上也是这样做的。它们在分配给数组时相关的原因是:
# Comma has precedence below assignment. 
# @a is assigned (1), 2 and 3 are discarded.
@a = 1, 2, 3; 

# @a is (1, 2, 3).
@a = (1, 2, 3);

关于你的问题“它是一个标量还是一个单元素列表”,在孤立的表达式中问这个问题是没有意义的,因为需要考虑上下文。在列表上下文中,所有内容都是列表;在标量上下文中,没有任何内容是列表。
推荐阅读:perlopperldataProgramming Perl

我喜欢使用Deparse来显示逗号运算符:perl -MO=Deparse -le 'my @s = 1,3,4; print "@s"' BEGIN { $/ = "\n"; $\ = "\n"; } my(@s) = 1, '???', '???'; print "@s"; -e 语法OK - brian d foy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接