tjw*_*992 4 perl operators comma scalar-context
我正在阅读" 编程Perl "并遇到一个似乎没有意义的奇怪例子.本书描述了Perl中的逗号运算符如何在标量上下文中使用时仅返回最后的结果.
例:
# After this statement, $stuff = "three"
$stuff = ("one", "two", "three");
Run Code Online (Sandbox Code Playgroud)
然后,这本书在几页之后给出了这个"反向逗号运算符"的例子(第82页)
# A "reverse comma operator".
return (pop(@foo), pop(@foo))[0];
Run Code Online (Sandbox Code Playgroud)
然而对我来说,这似乎并没有反过来......?
例:
# After this statement, $stuff = "three"
$stuff = reverse_comma("one", "two", "three");
# Implementation of the "reverse comma operator"
sub reverse_comma {
return (pop(@_), pop(@_))[0];
}
Run Code Online (Sandbox Code Playgroud)
这与正常的逗号运算符有何不同?结果是一样的,没有逆转!
这是一个糟糕的例子,应该被遗忘.
它的演示很简单:
通常,如果在标量上下文中有一系列由逗号分隔的表达式,则可以将其解释为逗号运算符的实例,该实例将计算到序列中的最后一项.
但是,如果您将该序列放在括号中并坚持[0]到最后,它会将该序列转换为列表并获取其第一个元素,例如
my $x = (1, 2, 3)[0];
Run Code Online (Sandbox Code Playgroud)
出于某种原因,本书将其称为"反向逗号运算符".这用词不当; 它只是一个列出第一个元素的列表.
这本书是混淆问题进一步通过pop在参数功能的两倍.这些从左到右进行评估,因此第一个pop评估为"three",第二个评估为"two".
在任何情况下:不要在实际代码中使用逗号或"反向逗号"运算符.两者都可能会让未来的读者感到困惑.
这是一个可爱而聪明的例子,但是过于考虑它会分散其目的.本书的这一部分展示了列表切片.除了列表中的内容之外,切换列表之外的任何内容都与示例的目的没有密切关系.
你只是在一本非常大的书的第82页(因为我们处于绑定方法的极限,我们实际上不能再适合任何页面了),所以我们没有太多可以向你投掷.在其他列表切片示例中,有一个我不会在实际代码中使用的聪明的例子.这是人为举例的诅咒.
但是,假设有一个反向逗号运算符.它必须评估逗号的两侧.很多答案都适合"只返回第一件事".但这不是特色.你必须访问每个表达,即使你保留其中一个.
考虑这个非常高级的版本,带有一系列匿名子程序,我立即取消引用,每个子程序打印一些然后返回结果:
use v5.10;
my $scalar = (
sub { say "First"; 35 } -> (),
sub { say "wantarray is ", 0+wantarray } -> (),
sub { say "Second"; 27 } -> (),
sub { say "Third"; 137 } -> ()
);
Run Code Online (Sandbox Code Playgroud)
由于赋值运算符比逗号运算符绑定得更紧密,所以parens只存在优先级.这里没有列表,即使看起来有一个.
输出显示Perl评估每个,即使它保留在最后一个:
First
wantarray is 0
Second
Third
Scalar is [137]
Run Code Online (Sandbox Code Playgroud)
内置不良的wantarray内置返回false,注意子例程认为它在标量上下文中.
现在,假设您想要翻转它,所以它仍然会评估每个表达式,但保留第一个表达式.您可以使用文字列表访问:
my $scalar = (
sub { say "First"; 35 } -> (),
sub { say "wantarray is ", 0+wantarray } -> (),
sub { say "Second"; 27 } -> (),
sub { say "Third"; 137 } -> ()
)[0];
Run Code Online (Sandbox Code Playgroud)
随着订阅的增加,右侧现在是一个列表,我拉出第一个项目.请注意,第二个子例程现在认为它在列表上下文中.我得到第一个子程序的结果:
First
wantarray is 1
Second
Third
Scalar is [35]
Run Code Online (Sandbox Code Playgroud)
但是,让我们把它放在子程序中.即使我不使用其他子程序的结果,我仍然需要调用每个子程序:
my $scalar = reverse_comma(
sub { say "First"; 35 },
sub { say "wantarray is ", 0+wantarray },
sub { say "Second"; 27 },
sub { say "Third"; 137 }
);
say "Scalar is [$scalar]";
sub reverse_comma { ( map { $_->() } @_ )[0] }
Run Code Online (Sandbox Code Playgroud)
或者,我会使用其他的结果吗?如果我做了稍微不同的事情怎么办?我将添加设置$last到计算表达式的副作用:
use v5.10;
my $last;
my $scalar = reverse_comma(
sub { say "First"; 35 },
sub { say "wantarray is ", 0+wantarray },
sub { say "Second"; 27 },
sub { say "Third"; 137 }
);
say "Scalar is [$scalar]";
say "Last is [$last]";
sub reverse_comma { ( map { $last = $_->() } @_ )[0] }
Run Code Online (Sandbox Code Playgroud)
现在我看到使标量逗号有趣的功能.它评估所有表达式,其中一些可能有副作用:
First
wantarray is 0
Second
Third
Scalar is [35]
Last is [137]
Run Code Online (Sandbox Code Playgroud)
tchrist对shell脚本很方便,这不是一个大秘密.Perl to csh转换器基本上是他的收件箱(或comp.lang.perl).在他的例子中你会看到一些类似于成语的shell.类似于使用一个语句交换两个数值的技巧:
use v5.10;
my $x = 17;
my $y = 137;
say "x => $x, y => $y";
$x = (
$x = $x + $y,
$y = $x - $y,
$x - $y,
);
say "x => $x, y => $y";
Run Code Online (Sandbox Code Playgroud)
副作用在那里很重要.
所以,回到Camel,我们有一个例子,其中有副作用的东西是pop数组运算符:
use v5.10;
my @foo = qw( g h j k );
say "list: @foo";
my $scalar = sub { return ( pop(@foo), pop(@foo) )[0] }->();
say "list: @foo";
Run Code Online (Sandbox Code Playgroud)
这表明评估了所有逗号两侧的每个表达式.我投入了子例程包装器,因为我们没有显示完整的示例:
list: g h j k
list: g h
Run Code Online (Sandbox Code Playgroud)
但是,这一点都不是该部分的重点,它正在索引到列表文字中.该示例的要点不是返回与其他示例或Perl功能不同的结果.假设逗号运算符采取不同的行为,它将返回相同的内容.该部分是关于列表切片并显示列表切片,因此列表中的内容不是重要部分.