我一直在研究采用块参数的Test::Warn软件包。 warning_like
方法具有签名warning_like BLOCK REGEXP, TEST_NAME
。我本以为在这种情况下,括号与其他子例程一样是可选的,因此以下内容应等效:
warning_like {bar()} qr/at Foo.pm line 5/, "Testname";
warning_like({bar()} qr/at Foo.pm line 5/, "Testname");
但是第二个带方括号的电话导致错误:
syntax error at t/testfile.t line 34, near "} qr/at Foo.pm line 5/"
Execution of t/testfile.t aborted due to compilation errors.
看起来该块改变了函数的调用方式。 warning_like
与according to the docs具有以下签名的map
类似; map BLOCK LIST
和map EXPR,LIST
。在这种情况下,方括号没有区别。
my @arr = ('a', 'b' ,'c', 'd', 'e');
my @mapped_block_1 = map( {uc($_)} @arr);
my @mapped_block_2 = map( uc, @arr);
my @mapped_expr_1 = map {uc($_)} @arr;
my @mapped_expr_2 = map uc, @arr;
这些之间有什么区别,为什么括号会影响warning_like
而不是map
的调用方式?为什么在将块用作参数的参数之间不需要逗号?
谢谢
答案 0 :(得分:1)
它们可以有所不同,因为warning_like ...
是子调用,而map ...
是操作员调用。
不同之处在于,处理map
的两个调用约定所需的代码是合理的,但是处理包含&
的任意原型(可能多次)需要妥协。
perlfunc导致以下问题:
本节中的函数可以用作表达式中的术语。它们分为两大类:列表运算符和命名一元运算符。
map
是运算符,就像+
一样。作为运算符,其语法独立于子调用的语法。
因此,这说明了两种语法为何可以不同的原因,但您还询问了为什么它们不同。
对于初学者来说,map
允许使用括号是有意义的,因为它将提供与其他“功能”的一致性。因此,问题是为什么sub name(&)
不允许使用name BLOCK
语法。为此,我不得不猜测,但我相信这是要避免极其复杂的解析器代码。
让我们从如何调用原型为&
的子程序开始。
mysub BLOCK # Parens forbidden.
mysub sub BLOCK # Parens allowed
mysub \&NAME # Parens allowed
mysub \&BLOCK # Parens allowed
mysub \&$NAME # Parens allowed
mysub \&$BLOCK # Parens allowed
Perl可以创建与这些规则完全匹配的解析规则。但是该子对象可以具有&@
,&$
,&$$
,&&
等原型,以此类推。拥有处理所有这些规则的规则是不可行的。相反,解析器仅处理以下内容:
mysub BLOCK LIST # Parens forbidden.
mysub LIST # Parens allowed
如果子名称后没有{
,则解析器首先将代码解析为一个简单的列表表达式,然后执行后续检查以查看生成的内容是否与原型匹配。您可以从错误消息中看到Perl做到了这一点。
请考虑以下内容:
$ perl -we'sub mysub(&) { ... } mysub("a'
Can't find string terminator '"' anywhere before EOF at -e line 1.
$ perl -we'sub mysub(&) { ... } mysub({});'
Type of arg 1 to main::mysub must be block or sub {} (not anonymous hash ({})) at -e line 1, near "})"
Execution of -e aborted due to compilation errors.
在第一个代码段中,即使其中不允许使用字符串文字,Perl也会给出一个错误,就好像它在解析字符串文字一样。
在第二个代码段中,我们可以看到{}
已成功解析为匿名哈希构造函数,即使那儿是不允许的。
顺便说一句,这也解释了为什么只有sub
的第一个参数时&
才可以省略。
sub mysub2(&&);
sub mysub3($&);
mysub2 BLOCK BLOCK # Not ok
mysub2 BLOCK sub BLOCK # ok
mysub2 BLOCK \&... # ok
mysub3 EXPR, BLOCK # Not ok
mysub3 EXPR, sub BLOCK # ok
mysub3 EXPR, \&... # ok
如果&...
的原型始终被解析为BLOCK LIST
(如果以{
开头)或LIST
(否则),则无法支持{{ 1}}。