use 5.016;
sub foo() {
say "foo";
}
sub main() {
foo(42);
}
main();
如果我运行上面的代码,它将显示下面的错误,这是我所期望的,因为foo
没有参数:
Too many arguments for main::foo at b.pl line 8, near "42)"
Execution of b.pl aborted due to compilation errors.
use 5.016;
sub main() {
foo(42);
}
sub foo() {
say "foo";
}
main()
但是如果我运行上面的代码,它可以正确地运行:
foo
为什么foo
这次接受参数?
1条答案
按热度按时间ar5n3qh51#
原型改变了函数的解析规则,所以为了被考虑,它们 * 必须 * 在函数调用被解析之前被知道,要么通过前面的定义,要么通过函数的预声明(
sub foo();
)。如果一个函数调用出现在函数的定义或预声明之前,那么它只能被解析为一个普通的(非原型化的)调用,假设解释器可以首先识别出它是一个函数。(在这个例子中,它可以,因为括号。)
然后,一旦定义出现,所指示的原型对已经解析的调用没有影响。然而,在其定义(或预声明)之后,对函数的进一步调用被原型化。添加另一位:
在函数定义之前的直接调用在运行时会产生一个警告,但在另一个sub中的调用不会。我不知道为什么从sub中的调用不会得到警告。(具有
fun_proto(42)
调用的sub的调用出现在fun_proto
定义之后,但所有这些-封闭的sub和其中的fun_proto
调用-都在定义之前编译。)要修复类似这样的代码,请在函数的任何提及之前添加一个预声明(“forward declaration”)。
也许你很清楚你在做什么,但我不得不问:你的代码中真的需要原型吗?它们有微妙之处,而它们的目的仅仅是允许调用用户定义的Subs,就像调用内置函数一样,* 而不是检查参数的数量和类型 *。
如果目的是检查参数,那么从v5.20开始perl就有了正确的子例程签名。
†这样做的一个真实的问题是,代码的编译取决于原型,所以当它们没有在预期的时候被应用时(比如这里),可能会导致安静的错误。
当那个sub被调用时(不带括号),它调用之后的任何东西都不会被用作它的参数--因为它不接受参数!--所以
后来(虽然很棘手)运行为
然而,如果原型定义不适用于这个调用,就像这个问题中的例子一样,那么表达式中sub后面的内容 * 被 * 作为它的参数列表,所以代码被编译为
没有警告。