$ perl -MO=Deparse -e 'sub f (&) { $_[0]->() }; print f {137}'
sub f (&) {
$_[0]->();
}
print f(sub {
137;
}
);
-e syntax OK
给予f一个匿名的sub,没问题:
$ perl -MO=Deparse -e 'sub f (&) { $_[0]->() }; print f sub {137}'
sub f (&) {
$_[0]->();
}
print f(sub {
137;
}
);
-e syntax OK
但是,使用parens和Perl认为块是一个匿名散列,即使你试图欺骗Perl将其视为一个代码块:
$ perl -MO=Deparse -e 'sub f (&) { $_[0]->() }; print f({137})'
Type of arg 1 to main::f must be block or sub {} (not anonymous hash ({})) at -e line 1, near "})
"
-e had compilation errors.
sub f (&) {
$_[0]->();
}
print &f({137});
$ perl -MO=Deparse -e 'sub f (&) { $_[0]->() }; print f({137;})'
syntax error at -e line 1, near ";}"
-e had compilation errors.
sub f (&) {
$_[0]->();
}
$ perl -MO=Deparse -e 'sub f (&) { $_[0]->() }; print f({return 137})'
Type of arg 1 to main::f must be block or sub {} (not anonymous hash ({})) at -e line 1, near "})
"
-e had compilation errors.
sub f (&) {
$_[0]->();
}
print &f({(return 137)});
3条答案
按热度按时间fwzugrvs1#
grep
采用BLOCK
或EXPR
。在您的第二个(工作)公式中,您提供了一个块,该块按预期使用本地
$_
值进行计算。在你的第一个公式中,你提供了一个表达式。这个表达式碰巧是一个匿名子例程,其中为每个被grepped的元素绑定了
$_
,但是 * 子例程本身不被求值 *。如果输入列表是
map
而不是grep
,你可以更清楚地看到发生了什么:当然,你也可以将临时子例程作为grep表达式的一部分进行求值,但语法很快就变得非常漂亮:
xwmevbvl2#
grep
不接受子例程。事实上,它甚至不是一个真实的的函数[1]。grep
可以通过两种方式之一调用,它们实际上只是语法上的不同:使用显式块或表达式参数。对于第二种形式,作为第一个“参数”传递给
grep
的表达式不仅被计算一次,而且对数组的每个元素都计算一次。在您给出的示例中,表达式参数是
sub { return "hello" eq $_ }
。我并没有说子例程会被调用。子例程永远不会被调用)每个列表元素一次。grep
返回任何块返回true的元素,“true”由标量值定义:如果标量值未定义、为空字符串或数字0(或其等效字符串“0”),则在布尔意义上将其解释为FALSE,如果是其他值,则解释为TRUE。
子例程不是未定义的,不是空字符串,也不是数字零,所以子例程是真值,因此输入列表的每个元素都满足(平凡的)块。
[1]在名称混乱的functions page中,许多内置的Perl函数不是真实的的函数,实际上是语言关键字。
sort
是一个臭名昭著的例子。没有办法用纯Perl编写一个行为像sort
的函数(因为它可以接受一个块,一个子例程名称,或者两者都不接受)。4sup72z83#
Perl的“函数”的语法有一点奇怪,它接受一个块参数,这是我的Perl烦恼之一。有一些事情是奇怪的,因为这是Perl的方式:
添加
sub
看起来不像Perl的块参数,因为这不是Perl解析事物的方式:但是当你使用这个特殊的块形式,去掉
sub
时,这是可行的,Perl知道如何解析这些特殊情况,因为Perl知道如何解析这些特殊情况:我希望Perl能对匿名函数有一个更一般的概念,这是Raku解决的问题之一。我认为Ruby在可选块方面也做得很好。
现在,让我们使用prototypes来创建我们自己的函数
f
,它带有一个block参数(这通常是最好的主意)。对于用户定义的函数来说,情况与Perl的内置函数略有不同(我知道这让人抓狂):给予
f
一个区块,没问题:给予
f
一个匿名的sub
,没问题:但是,使用parens和Perl认为块是一个匿名散列,即使你试图欺骗Perl将其视为一个代码块:
有时候事情就是这样。