赋值解构和运算符优先级

Whi*_*ist 10 rakudo raku

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

这允许我们做这样的事情:

my @array = 1, 2, 3;
Run Code Online (Sandbox Code Playgroud)

我不明白的是为什么要这样做:

sub test() { return 1, 2 }
my ($a, $b);
$a, $b = test();
Run Code Online (Sandbox Code Playgroud)

$b[1 2]$a没有值的情况下被分配。

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

($a, $b) = test();
Run Code Online (Sandbox Code Playgroud)

Raku 的语义有很多微妙之处,我想我对 Perl 的思考太多了。

就像 raiph 在评论中所说的那样,我最初的假设是逗号运算符比赋值运算符具有更高的优先级,这是错误的。这是由于运算符优先级表的呈现存在问题,该表没有按优先级顺序显示运算符。这解释了我的示例中 Raku 的实际行为。

Jon*_*ton 6

运算=符本身始终是项目赋值级别,比逗号更严格。但是,它可以应用“子优先级”,这就是它与后面的表达式中的任何其他中缀进行比较的方式。考虑之前解析的术语=,并且:

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

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

$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
Run Code Online (Sandbox Code Playgroud)

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

@foo = 1, 2;      # List assignment into @foo two values
$foo = 1, 2;      # Assignment of 1 into $foo, 2 is dead code
Run Code Online (Sandbox Code Playgroud)

这些适用于=初始化程序(在my $var声明之后)。这意味着:

loop (my $i = 0, my $j = $end; $i < $end; $i++, $j--) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

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

实际上,该规则意味着我们可以对数组和散列变量进行无括号初始化,同时仍然具有标量初始化列表,如loop

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

($a, $b) = test();
Run Code Online (Sandbox Code Playgroud)

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

在这种情况下:

sub test() { return 1, 2 }
my ($a, $b);
$a, $b = test();
Run Code Online (Sandbox Code Playgroud)

优先级解析器先看到,中缀,然后再看到=中缀。中缀=本身比逗号更紧密(项目分配优先级);子优先级仅对在之后解析的中缀可见=(这里没有)。

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

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

最终不会分组为(my $i = 0), (my @lagged = Nil, |@values),而是分组为(my $i = 0, my @lagged) = Nil, |@values,这是相当不那么有用的。