Perl 5 中存在哪些伪运算符?
Posted
技术标签:
【中文标题】Perl 5 中存在哪些伪运算符?【英文标题】:What pseudo-operators exist in Perl 5? 【发布时间】:2011-02-23 06:44:18 【问题描述】:我目前正在记录 Perl 5 的所有运算符(请参阅perlopref GitHub 项目),并且我决定也包括 Perl 5 的伪运算符。对我来说,Perl 中的伪运算符是任何看起来像运算符的东西,但实际上不仅仅是一个运算符或某种其他语法。我已经记录了我熟悉的四个:
()=
countof 运算符
=()=
goatse/countof 运算符
~~
标量上下文运算符
爱斯基摩亲吻操作员
这些伪算子还有哪些其他名称,你知道我遗漏了哪些伪算子吗?
=head1 Pseudo-operators
There are idioms in Perl 5 that appear to be operators, but are really a
combination of several operators or pieces of syntax. These pseudo-operators
have the precedence of the constituent parts.
=head2 ()= X
=head3 Description
This pseudo-operator is the list assignment operator (aka the countof
operator). It is made up of two items C<()>, and C<=>. In scalar context
it returns the number of items in the list X. In list context it returns an
empty list. It is useful when you have something that returns a list and
you want to know the number of items in that list and don't care about the
list's contents. It is needed because the comma operator returns the last
item in the sequence rather than the number of items in the sequence when it
is placed in scalar context.
It works because the assignment operator returns the number of items
available to be assigned when its left hand side has list context. In the
following example there are five values in the list being assigned to the
list C<($x, $y, $z)>, so C<$count> is assigned C<5>.
my $count = my ($x, $y, $z) = qw/a b c d e/;
The empty list (the C<()> part of the pseudo-operator) triggers this
behavior.
=head3 Example
sub f return qw/a b c d e/
my $count = ()= f(); #$count is now 5
my $string = "cat cat dog cat";
my $cats = ()= $string =~ /cat/g; #$cats is now 3
print scalar( ()= f() ), "\n"; #prints "5\n"
=head3 See also
L</X = Y> and L</X =()= Y>
=head2 X =()= Y
This pseudo-operator is often called the goatse operator for reasons better
left unexamined; it is also called the list assignment or countof operator.
It is made up of three items C<=>, C<()>, and C<=>. When X is a scalar
variable, the number of items in the list Y is returned. If X is an array
or a hash it it returns an empty list. It is useful when you have something
that returns a list and you want to know the number of items in that list
and don't care about the list's contents. It is needed because the comma
operator returns the last item in the sequence rather than the number of
items in the sequence when it is placed in scalar context.
It works because the assignment operator returns the number of items
available to be assigned when its left hand side has list context. In the
following example there are five values in the list being assigned to the
list C<($x, $y, $z)>, so C<$count> is assigned C<5>.
my $count = my ($x, $y, $z) = qw/a b c d e/;
The empty list (the C<()> part of the pseudo-operator) triggers this
behavior.
=head3 Example
sub f return qw/a b c d e/
my $count =()= f(); #$count is now 5
my $string = "cat cat dog cat";
my $cats =()= $string =~ /cat/g; #$cats is now 3
=head3 See also
L</=> and L</()=>
=head2 ~~X
=head3 Description
This pseudo-operator is named the scalar context operator. It is made up of
two bitwise negation operators. It provides scalar context to the
expression X. It works because the first bitwise negation operator provides
scalar context to X and performs a bitwise negation of the result; since the
result of two bitwise negations is the original item, the value of the
original expression is preserved.
With the addition of the Smart match operator, this pseudo-operator is even
more confusing. The C<scalar> function is much easier to understand and you
are encouraged to use it instead.
=head3 Example
my @a = qw/a b c d/;
print ~~@a, "\n"; #prints 4
=head3 See also
L</~X>, L</X ~~ Y>, and L<perlfunc/scalar>
=head2 X Y
=head3 Description
This pseudo-operator is called the Eskimo-kiss operator because it looks
like two faces touching noses. It is made up of an closing brace and an
opening brace. It is used when using C<perl> as a command-line program with
the C<-n> or C<-p> options. It has the effect of running X inside of the
loop created by C<-n> or C<-p> and running Y at the end of the program. It
works because the closing brace closes the loop created by C<-n> or C<-p>
and the opening brace creates a new bare block that is closed by the loop's
original ending. You can see this behavior by using the L<B::Deparse>
module. Here is the command C<perl -ne 'print $_;'> deparsed:
LINE: while (defined($_ = <ARGV>))
print $_;
Notice how the original code was wrapped with the C<while> loop. Here is
the deparsing of C<perl -ne '$count++ if /foo/; print "$count\n"'>:
LINE: while (defined($_ = <ARGV>))
++$count if /foo/;
print "$count\n";
Notice how the C<while> loop is closed by the closing brace we added and the
opening brace starts a new bare block that is closed by the closing brace
that was originally intended to close the C<while> loop.
=head3 Example
# count unique lines in the file FOO
perl -nle '$seen$_++ print "$_ => $seen$_" for keys %seen' FOO
# sum all of the lines until the user types control-d
perl -nle '$sum += $_ print $sum'
=head3 See also
L<perlrun> and L<perlsyn>
=cut
【问题讨论】:
在旁注中,恕我直言,爱斯基摩人的吻很有趣 XD+=
、-=
、/=
、*=
、**=
家族和短路运算符 ||= or //=
怎么样?它们是伪操作吗?
@klex 是的,一旦你看到它,你就无法取消它。有点像联邦快递中的箭头。 goatse 操作员也是如此,但这不太令人愉快。
@Zaid 是的,我已经拥有了 perlop 中的所有内容以及 perlfunc 中记录的文件测试(尽管它们目前只是占位符)。我在这里追求的是看起来像运算符的习语。该项目的用途之一是 Padre Perl IDE 中的上下文相关帮助。这个想法是你按下 F1 并且光标下的任何字符串都与所有 Perl 函数和运算符进行模糊匹配。
@Shaggy Frog 啊,你以为我命名了操作员;我没有,我只是在记录使用情况。这就是它的名字。尝试谷歌搜索:google.com/search?q=goatse+operator
【参考方案1】:
不错的项目,这里有几个:
scalar x!! $value # conditional scalar include operator
(list) x!! $value # conditional list include operator
'string' x/pattern/ # conditional include if pattern
"@[ list ]" # interpolate list expression operator
"$\scalar" # interpolate scalar expression operator
!! $scalar # scalar -> boolean operator
+0 # cast to numeric operator
.'' # cast to string operator
($value or next)->depends_on_value() # early bail out operator
# aka using next/last/redo with bare blocks to avoid duplicate variable lookups
# might be a stretch to call this an operator though...
sub\@_->( list ) # list capture "operator", like [ list ] but with aliases
【讨论】:
我喜欢x!!
技巧,但通常在我真正需要它时忘记它,并最终改为使用 ( $cond ? $foo : ( ) )
。
嗯!我在整体帖子 +1 和“早期救助”运营商发出的“维护噩梦”光环 -1 之间左右为难。
@DVK 给他 +1,我们不鼓励这种行为,只是记录它,这样当你遇到它时,你就有机会理解它。
...我很难说服怀疑论者,他们可以编写高质量、可维护的可读 Perl 代码,而无需人们积极尝试通过推广代码 golphish 成语来破坏它:) ;)
我今天早些时候已经添加了这样一个部分,上面写着“注意通常有更好的方法来做所有这些事情,这些方法对于在你之后维护你的代码的人来说会更容易理解。”【参考方案2】:
在 Perl 中,这些通常称为“秘密运算符”。
“秘密操作员”can be had here 的部分列表。最好和最完整的列表可能是拥有Philippe Bruhad aka BooK 和他的Secret Perl Operators 谈话,但我不知道它在哪里可用。你可以问他。您可能可以从Obfuscation, Golf and Secret Operators 收集更多信息。
【讨论】:
嗯,我不知道是否值得以这种方式记录所有这些(坦率地说,我只是试图单独记录正常的操作,我已经筋疲力尽了)。现在我优先考虑我希望在非混淆代码中看到的那些。【参考方案3】:别忘了Flaming X-Wing=<>=~
。
Fun With Perl 邮件列表将证明对您的研究很有用。
【讨论】:
【参考方案4】:“去”和“被接近”运算符:
$x = 10;
say $x while $x --> 4;
# prints 9 through 4
$x = 10;
say $x while 4 <-- $x;
# prints 9 through 5
它们不是 Perl 独有的。
【讨论】:
虽然看起来很特别,但这些东西是鼓励 Obiwan 错误的绝佳方式...... :) 我发现这个运算符的 SO 讨论非常有趣:What is the name of this operator: “-->”? 是的,我肯定见过有人用过这些。【参考方案5】:从this question,我发现%
运算符将列表转换为哈希。有用的
需要散列参数(而不是散列赋值)的上下文。
@list = (a,1,b,2);
print values @list; # arg 1 to values must be hash (not array dereference)
print values %@list # prints nothing
print values (%temp=@list) # arg 1 to values must be hash (not list assignment)
print values %@list # success: prints 12
如果@list
不包含任何重复键(奇数元素),则此运算符还提供了一种访问列表的奇数或偶数元素的方法:
@even_elements = keys %@list # @list[0,2,4,...]
@odd_elements = values %@list # @list[1,3,5,...]
【讨论】:
这也允许直接访问由函数返回的哈希元素(使用 $sub_name(): sub foo return (a => 1, b => 2, c => 3) 打印 $foob;【参考方案6】:Perl 秘密运算符现在在 CPAN 上有一些参考(几乎是官方的,但它们是“秘密”)文档:perlsecret
【讨论】:
【参考方案7】:您有两个“countof”(伪)运算符,我看不出它们之间的区别。
来自“countof 运算符”的例子:
my $count = ()= f(); #$count is now 5
my $string = "cat cat dog cat";
my $cats = ()= $string =~ /cat/g; #$cats is now 3
来自“goatse/countof 运算符”的例子:
my $count =()= f(); #$count is now 5
my $string = "cat cat dog cat";
my $cats =()= $string =~ /cat/g; #$cats is now 3
两组示例都是相同的,模空格。您认为它们是两个不同的伪算子的理由是什么?
【讨论】:
因为有些人用一种方式写它,而另一些人用不同的方式。而且示例并不完全相同,您遗漏了print scalar( ()= f() ), "\n"; #prints "5\n"
,而=()=
无法做到这一点。
@Chas.:是的,我跳过了那个,但推理很明显:()=
是实际工作的。完整山羊上的前导=
只是将()=
生成的结果分配给一个变量,您在函数调用中没有这样做。仅仅因为有些人包含空格而其他人不包含空格,就说它们是不同的运算符,就像说 1 + 1 = 2
和 1+1=2
是不同的表达式,使用不同的 +
和 =
运算符,“因为有些人一种写法,另一种写另一种写法"。
我同意你的观点,除了它们看起来像不同的运算符并且有不同的描述。想象一下,您不知道如何解析my $x =()= /a/g;
,您是希望单独记录=()=
,还是想弄清楚它记录在()=
下?开始此文档的最初原因是新手可以在 perlop 中找到||=
的文档。【参考方案8】:
“布尔一或零”运算符怎么样:1&!!
例如:
my %result_of = (
" 1&!! '0 but true' " => 1&!! '0 but true',
" 1&!! '0' " => 1&!! '0',
" 1&!! 'text' " => 1&!! 'text',
" 1&!! 0 " => 1&!! 0,
" 1&!! 1 " => 1&!! 1,
" 1&!! undef " => 1&!! undef,
);
for my $expression ( sort keys %result_of)
print "$expression = " . $result_of$expression . "\n";
给出以下输出:
1&!! '0 but true' = 1
1&!! '0' = 0
1&!! 'text' = 1
1&!! 0 = 0
1&!! 1 = 1
1&!! undef = 0
【讨论】:
【参考方案9】:<< >>
运算符,用于multi-line comments:
<<q==q>>;
This is a
multiline
comment
q
【讨论】:
以上是关于Perl 5 中存在哪些伪运算符?的主要内容,如果未能解决你的问题,请参考以下文章