这是一个可爱而聪明的例子,但想得太用力会分散其目的。这本书的那部分正在展示列表切片。除了对列表进行切片之外,无论列表中有什么,都与示例的目的无关。
您只在一本非常大的书的第 82 页上(我们实际上无法再放入更多页面,因为我们处于装订方法的限制),所以我们可以扔给您的东西不多。在其他列表切片示例中,有一个我不会在实际代码中使用的聪明的示例。这是人为例子的诅咒。
但是假设有一个反逗号运算符。它必须评估逗号的两边。许多答案都适合“只返回第一件事”。但这不是功能。即使您保留其中一个,您也必须访问每个表达式。
考虑一下这个非常高级的版本,它带有一系列我立即取消引用的匿名子例程,每个子例程都打印一些内容然后返回一个结果:
use v5.10;
my $scalar = (
sub { say "First"; 35 } -> (),
sub { say "wantarray is ", 0+wantarray } -> (),
sub { say "Second"; 27 } -> (),
sub { say "Third"; 137 } -> ()
);
括号仅用于优先级,因为赋值运算符比逗号运算符绑定得更紧密。这里没有列表,尽管看起来有一个。
输出显示 Perl 评估了每一个,即使它保留在最后一个:
First
wantarray is 0
Second
Third
Scalar is [137]
名称不佳的wantarray内置函数返回false,说明子例程认为它处于标量上下文中。
现在,假设您想翻转它,以便它仍然评估每个表达式,但保留第一个。您可以使用文字列表访问:
my $scalar = (
sub { say "First"; 35 } -> (),
sub { say "wantarray is ", 0+wantarray } -> (),
sub { say "Second"; 27 } -> (),
sub { say "Third"; 137 } -> ()
)[0];
随着订阅的添加,右侧现在是一个列表,我拉出第一个项目。请注意,第二个子例程现在认为它在列表上下文中。我得到第一个子程序的结果:
First
wantarray is 1
Second
Third
Scalar is [35]
但是,让我们把它放在一个子程序中。即使我不会使用其他子程序的结果,我仍然需要调用每个子程序:
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] }
或者,我会使用其他人的结果吗?如果我做了一些稍微不同的事情怎么办。$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] }
现在我看到了使标量逗号变得有趣的特性。它评估所有表达式,其中一些可能有副作用:
First
wantarray is 0
Second
Third
Scalar is [35]
Last is [137]
tchrist 使用 shell 脚本很方便,这并不是什么大秘密。Perl 到 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";
副作用在那里很重要。
所以,回到骆驼,我们有一个例子,其中有副作用的东西是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";
这表明所有逗号两侧的每个表达式都被评估。因为我们没有展示一个完整的例子,所以我加入了子例程包装器:
list: g h j k
list: g h
但是,这些都不是该部分的重点,它正在索引列表文字。该示例的重点不是返回与其他示例或 Perl 功能不同的结果。假设逗号运算符的行为不同,它会返回相同的内容。该部分是关于列表切片的,并且正在展示列表切片,因此列表中的内容并不是重要的部分。