赋值解构和运算符优先级

Assignment destructuring and operator precedence

文档中说逗号运算符比赋值运算符 = 具有更高的优先级,这与 Perl 中的有很大不同,因此我们可以在某些上下文中删除括号。

这让我们可以做这样的事情:

my @array = 1, 2, 3;

我不明白的是为什么什么时候做这样的事情:

sub test() { return 1, 2 }
my ($a, $b);
$a, $b = test();

$b 被赋值 [1 2]$a 没有值。

虽然我假设以下内容是等价的,因为逗号运算符比赋值更严格。

($a, $b) = test();

Raku 的语义有很多微妙之处,我想我在 Perl 方面想得太多了。

正如 raiph 在评论中所说,我最初假设逗号运算符的优先级高于赋值运算符是错误的。这是由于运算符优先级的呈现问题 table,它没有按优先顺序显示运算符。 这为我的示例解释了 Raku 的实际行为。

= 运算符本身始终是项目分配级别,比逗号更紧。但是,它可能会应用“sub-precedence”,这是将它与后面的表达式中的任何其他中缀进行比较的方式。考虑 = 之前解析的术语,并且:

  • 在赋值给 Scalar 变量的情况下,= 运算符的工作方式与任何其他项目赋值优先级运算符一样,比 [=20= 的优先级更严格]
  • 在任何其他情况下,其相对于后续中缀的优先级为列表前缀,比,
  • 的优先级宽松

考虑一些情况(首先,它不影响任何东西):

$foo = 42;     # $ sigil, so item assignment precedence after
@foo = 1;      # @ sigil, so list assignment precedence after
@foo[0] = 1;   # postcircumfix (indexing operator) means list assignment after...
$foo[0] = 1;   # ...always, even in this case

如果我们左边是一个变量,右边是一个列表,那么:

@foo = 1, 2;      # List assignment into @foo two values
$foo = 1, 2;      # Assignment of 1 into $foo, 2 is dead code

这些适用于 = 初始值设定项(在 my $var 声明之后)。这意味着:

loop (my $i = 0, my $j = $end; $i < $end; $i++, $j--) {
    ...
}

将导致 $i 被分配 0$j 被分配 $end

实际上,该规则意味着我们可以对数组和散列变量进行 parentheses-free 初始化,同时仍然具有标量初始化列表,如 loop 中的情况。

转向问题中的例子。首先,这个:

($a, $b) = test();

解析单个术语,然后遇到 =。比较任何后续中缀时的优先级将是列表前缀(比 , 更宽松)。但是,这里没有更多的中缀,所以这并不重要。

在这种情况下:

sub test() { return 1, 2 }
my ($a, $b);
$a, $b = test();

优先解析器看到 , 中缀,然后是 = 中缀。 = 中缀本身比逗号更紧(项目分配优先级); sub-precedence 仅对 = 之后解析的中缀可见(这里有 none)。

请注意,如果不是这样,并且将优先级转换应用于整个表达式,则:

loop (my $i = 0, my @lagged = Nil, |@values; $i < @values; $i++) {
    ...
}

最终不会分组为 (my $i = 0), (my @lagged = Nil, |@values),而是分组为 (my $i = 0, my @lagged) = Nil, |@values,后者的用处不大。