Perl";反向逗号运算符“;(示例摘自《Perl编程》,第4版)
我在读“”时,遇到了一个奇怪的例子,似乎没有什么意义。本书描述了Perl中的逗号运算符在标量上下文中使用时如何仅返回最后一个结果 示例:Perl";反向逗号运算符“;(示例摘自《Perl编程》,第4版),perl,operators,comma,scalar-context,Perl,Operators,Comma,Scalar Context,我在读“”时,遇到了一个奇怪的例子,似乎没有什么意义。本书描述了Perl中的逗号运算符在标量上下文中使用时如何仅返回最后一个结果 示例: # After this statement, $stuff = "three" $stuff = ("one", "two", "three"); # After this statement, $stuff = "three" $stuff = reverse_comma("one", "two", "three"); # Implementation
# After this statement, $stuff = "three"
$stuff = ("one", "two", "three");
# After this statement, $stuff = "three"
$stuff = reverse_comma("one", "two", "three");
# Implementation of the "reverse comma operator"
sub reverse_comma {
return (pop(@_), pop(@_))[0];
}
几页之后,本书给出了“反向逗号运算符”的示例(第82页)
然而,对我来说,这似乎根本不是相反的
示例:
# After this statement, $stuff = "three"
$stuff = ("one", "two", "three");
# After this statement, $stuff = "three"
$stuff = reverse_comma("one", "two", "three");
# Implementation of the "reverse comma operator"
sub reverse_comma {
return (pop(@_), pop(@_))[0];
}
这与普通的逗号运算符有何相反之处?结果是一样的,不是相反的
这是一个精确的页面。这个例子接近底部。这是一个可爱而聪明的例子,但如果想得太多,就会偏离它的目的。这本书的那一部分正在展示一系列的片段。除了切片列表之外的任何内容,无论列表中有什么内容,都与示例的目的无关
你只在一本非常大的书的第82页上(我们实际上无法容纳更多的页面,因为我们已经达到了绑定方法的极限),所以我们无法向你扔太多东西。在其他列表切片示例中,有一个我不会在实际代码中使用的聪明示例。这是人为的例子的诅咒 但假设有一个反逗号运算符。它必须计算逗号的两边。许多答案都适用于“第一件事就是归还”。但这不是功能。你必须访问每一个表情,即使你保留了其中的一个 考虑一下这个非常高级的版本,它包含一系列我立即取消引用的匿名子例程,每个子例程打印一些内容,然后返回一个结果:
use v5.10;
my $scalar = (
sub { say "First"; 35 } -> (),
sub { say "wantarray is ", 0+wantarray } -> (),
sub { say "Second"; 27 } -> (),
sub { say "Third"; 137 } -> ()
);
paren仅用于优先级,因为赋值运算符比逗号运算符绑定得更紧密。这里没有列表,尽管看起来有一个
输出显示Perl对每一个都进行了求值,即使它保留了最后一个:
First
wantarray is 0
Second
Third
Scalar is [137]
命名不好的内置函数返回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)。你会在他的例子中看到一些外壳式的习惯用法。类似于用一条语句交换两个数值的技巧:
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";
副作用很重要
那么,回到Camel,我们有一个例子,其中有副作用的是数组操作符:
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";
$scalar = ("one", "two", "three");
# $scalar now contains "three"
$scalar = ("one", "two", "three")[0];
# $scalar now contains "one"
这表明对所有逗号任一侧的每个表达式都进行了求值。我加入了子程序包装器,因为我们没有显示完整的示例:
list: g h j k
list: g h
但是,这些都不是该节的重点,该节将索引转换为列表文字。该示例的要点是不返回与其他示例或Perl特性不同的结果。假设逗号运算符的操作不同,则返回相同的结果。本节是关于列表片段的,并展示列表片段,因此列表中的内容不是重要部分。这是一个糟糕的示例,应该忘记 它演示的内容很简单:
- 通常,如果在标量上下文中有一个由逗号分隔的表达式序列,则可以将其解释为逗号运算符的实例,其计算结果为序列中的最后一项
- 但是,如果您将该序列放在括号中,并在末尾粘贴
,它会将该序列转换为一个列表,并获取其第一个元素,例如[0]
出于某种原因,这本书称之为“反向逗号运算符”。这是用词不当;这只是一个列表,它的第一个元素已被获取my $x = (1, 2, 3)[0];
pop
函数,进一步混淆了问题。这些值是从左到右计算的,因此第一个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";
$scalar = ("one", "two", "three");
# $scalar now contains "three"
$scalar = ("one", "two", "three")[0];
# $scalar now contains "one"
反向逗号运算符:
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";
$scalar = ("one", "two", "three");
# $scalar now contains "three"
$scalar = ("one", "two", "three")[0];
# $scalar now contains "one"
这是一个“反向逗号”,因为$scalar
获取第一个表达式的结果,其中普通逗号运算符给出最后一个表达式。(如果您了解Lisp,这就像progn
和prog1
之间的区别一样)
“反向逗号运算符”作为子例程的实现如下所示:
sub reverse_comma {
return shift @_;
}
普通逗号将计算其操作数,然后返回右侧操作数的值
my $v = $a, $b
将$v
设置为$b
为了演示列表切片,Camel提出了一些类似于逗号运算符的代码,但会对其操作数求值,然后返回左侧操作数的值
my $v = $a, $b
类似的事情可以通过列表切片来完成,比如
my $v = ($a, $b)[0]
my $last = pop @foo;
pop @foo;
return $last;
将$v
设置为$a
就这些