为什么Perl子例程需要“&”?

3
以下文件无法编译:
sub s {
    return 'foo';
}
sub foo {
    my $s = s();
    return $s if $s;
    return 'baz?';
}
< p > perl -c 的错误是:

syntax error at foobar.pl line 5 near "return"
  (Might be a runaway multi-line ;; string starting on line 3)
foobar.pl had compilation errors.

但是,如果我将s()替换为&s(),它可以正常工作。你能解释一下原因吗?


7
我想你是在使用s///替换操作符时遇到了冲突。 - Paul Dixon
1
@Axeman,m()可能会出现未初始化警告,但q()确实会保持沉默。 - ikegami
1
@ikegami,是的,当我尝试它们时,正是我得到的结果。而且m()始终返回1,如果$_未初始化,则会出现警告。 - Axeman
3
顺便提一下,除了你面临的技术问题之外,你应该考虑始终100%使用自我记录标识符。从软件工程角度来看,给子程序命名为“s”是非常不好的做法,与你遇到的Perl特定技术问题无关。 - DVK
1
@GeorgeBailey - “永远编写代码时要像维护代码的人是一个完全的杀人狂,他知道你住在哪里一样”。 - DVK
显示剩余3条评论
3个回答

13

&前缀明确表示您想调用自己的名为"s"的函数,而不是任何同名的内置函数。在这种情况下,它将其与替换运算符(例如$stuff =~ s///;,也可以写成s()())混淆。

这里有一篇PerlMonks关于&符号作用的讨论


1
你是正确的。当将sub s$s替换为sub t$t时 - 就不会出现失败情况。 - Galimov Albert
2
我意识到这可能只是一个简化的测试案例,但这也可以是使用更具描述性的函数名称的示例。它们可能不太可能被误认为其他东西。 - Mike

3
您所面临的问题,如已经指出的那样,是s()被解释为s///替换运算符。在函数名称前加上&是一个解决方法,但我不会说这一定是正确的。在perldoc perlsub中,对于调用子例程,有以下说明:
NAME(LIST);  # & is optional with parentheses.
NAME LIST;   # Parentheses optional if predeclared/imported.
&NAME(LIST); # Circumvent prototypes.
&NAME;       # Makes current @_ visible to called subroutine.

这里的&符号仅用于区分内置函数与自定义函数。

除了重命名子例程之外,处理这个问题的“正确”方法是意识到表面下正在发生的事情。当你说

s();

你真正想表达的是:
CORE::s();  

当你想表达的意思是
main::s();

呵呵,没想到 perl -e"CORE::s/a/b/" 也能用。我并不感到惊讶;只是从来没有想过。 - ikegami
1
感觉有点奇怪,不是吗。 :) - TLP

1
 my $s = 's'->();

也可以正常工作 - 奇怪的是在 strict 模式下。


@TLP,只适用于常量名称,这是可以的。另一方面,在严格模式下,my $n = 's'; \&$n 也能正常工作。这就不太好了。 - ikegami
@ikegami 这很奇怪。&$n 在严格模式下被捕获,但当它被转换为代码引用时却没有。听起来有点像一个 bug。 - TLP
@TLP,这意味着您可以使用 (\&$n)->() 来规避严格模式,而不是 $n->()。虽然更易读的方法是使用 no strict 'refs'; - ikegami
我听说有人声称这个严格的漏洞是为了允许&$AUTOLOAD; 不知道这是否真实存在或只是一种合理化解释。 - ysth
@ysth,我可以看出这可能是这种情况。这可能是为了支持有点过时的间接方法调用。然而,使用strictuse strict -no_autoload => 1;use strict -no_indirect => 1来进行调整会很好,并获得更严格的限制——甚至是use strict -absolutely_no_nonmethod_strings_as_subs => 1。 (我仍然喜欢偶尔使用字符串,因此在某种程度上获得使用类似Smalltalk的“object message”范例,而不是被锁定在类似C的准虚表中。) - Axeman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接