让Perl展望子原型

时间:2018-12-30 03:18:31

标签: perl function-prototypes

Perl太宽容了:如果将额外的参数传递给sub,则它们将被忽略。

为避免这种情况,我想使用原型来确保每个sub都具有正确数量的参数。

只要我在使用原型之前声明了原型,这就可以正常工作

sub mysub($);
sub mysub2($);

mysub(8);
mysub(8,2); # Complain here                                                            

sub mysub($) {
    mysub2($@);
}

sub mysub2($) {
    if($_[0] == 1) {
        mysub(2);
    }
    print $@;
}

但我真的很讨厌将其拆分。我宁愿Perl读取完整文件,看看是否还有声明。所以我想写一些类似的东西:

use prototypes_further_down; # This does not work

mysub(8);
mysub(8,2); # Complain here                                                            

sub mysub($) {
    mysub2($@);
}

sub mysub2($) {
    if($_[0] == 1) {
        mysub(2);
    }
    print $@;
}

我可以以某种方式要求Perl这样做吗?

1 个答案:

答案 0 :(得分:4)

  

为避免这种情况,我想使用原型来确保每个sub都具有正确数量的参数。

不,您不会。尽管名称相似,但是Perl原型不是您父亲的函数原型。引用The Problem with Prototypes(强调我),

  

Perl 5的原型有两个目的。首先,它们提示解析器更改其解析子例程及其参数的方式。其次,它们改变了Perl 5在执行子例程时处理它们的参数的方式。 新手常见的错误是假定它们与其他语言的子例程签名具有相同的语言用途。这不是真的。

除了它们不具有相同的预期目的之外,绕过原型也是微不足道的,因此它们不能真正防止有人故意以“错误”的方式调用您的代码。正如perldoc perlsub告诉我们的,

  

函数声明在编译时必须可见。原型仅影响对函数的新式调用的解释,其中新式定义为不使用&字符。换句话说,如果您像内置函数一样调用它,那么它的行为就像内置函数一样。如果您将其称为老式子例程,则其行为类似于老式子例程。从这个规则自然可以得出结论,原型对诸如\&foo之类的子例程引用或诸如&{$subref}$subref->()之类的间接子例程调用没有影响。

     

方法调用也不受原型的影响,因为要调用的函数在编译时不确定,因为调用的确切代码取决于继承。

即使您可以抱怨mysub(8,2)&mysub(8,2)$subref = \&mysub; $subref->(8,2)或(如果mysubpackage MyModule中的对象方法){{ 1}}可以正常工作。

如果要验证使用内核Perl(在5.20之前)如何调用子程序,则需要在子程序主体中自己执行验证。 Perl 5.20和更高版本在子声明中有一个Signatures扩展名(在撰写本文时为“实验性”),它可能适合您的目的,但我自己从未使用过它,因此我无法与其交流有效性或局限性。还有许多CPAN模块可用于处理这种事情,您可以通过搜索“签名”或“原型”之类的东西来找到它们。

无论采用哪种方法,除非使用了不正确的函数签名,否则您将无法获得有关错误函数签名的编译时错误。在您的示例中,两个子对象相互调用,可以通过使用向前声明预先建立其签名来实现:

$o = MyModule->new; $o->mysub(8,2)