在另一个Stack Overflow问题中, Leon Timmermans断言:
我建议你不要使用原型.它们有它们的用途,但对大多数情况并非如此,绝对不是在这个例子中.
为什么这可能是真的(或其他)?我几乎总是为我的Perl函数提供原型,而且我从来没有见过其他任何人说使用它们的坏事.
如果使用正确,原型也不错.困难在于Perl的原型不像人们通常期望的那样工作.具有其他编程语言背景的人倾向于期望原型提供检查函数调用是否正确的机制:即,他们具有正确数量和类型的参数.Perl的原型并不适合这项任务.这是滥用,这是不好的.Perl的原型有一个非常不同的目的:
原型允许您定义与内置函数类似的函数.
括号是可选的.
上下文强加于参数.
例如,您可以定义这样的函数:
sub mypush(\@@) { ... }
并称之为
mypush @array, 1, 2, 3;
无需编写\
以获取对数组的引用.
简而言之,原型可以让你创建自己的语法糖.例如,Moose框架使用它们来模拟更典型的OO语法.
这非常有用,但原型非常有限:
它们必须在编译时可见.
他们可以被绕过.
将上下文传播到参数可能会导致意外行为.
它们使得使用除严格规定的表格之外的任何东西来调用函数变得困难.
有关所有血腥细节,请参阅perlsub中的Prototypes.
问题是Perl的功能原型并没有像人们认为的那样做.它们的目的是允许您编写将像Perl的内置函数一样进行解析的函数.
首先,方法调用完全忽略原型.如果您正在进行OO编程,那么您的方法所具有的原型并不重要.(所以他们不应该有任何原型.)
其次,原型并未严格执行.如果使用子程序调用&function(...)
,则忽略原型.所以他们并没有真正提供任何类型的安全.
第三,他们是远距离的幽灵行动.(特别是$
原型,它导致在标量上下文中计算相应的参数,而不是默认的列表上下文.)
特别是,它们使得从数组传递参数变得困难.例如:
my @array = qw(a b c); foo(@array); foo(@array[0..1]); foo($array[0], $array[1], $array[2]); sub foo ($;$$) { print "@_\n" } foo(@array); foo(@array[0..1]); foo($array[0], $array[1], $array[2]);
打印:
a b c a b a b c 3 b a b c
以及3个警告main::foo() called too early to check prototype
(如果启用了警告).问题是在标量上下文中计算的数组(或数组切片)返回数组的长度.
如果您需要编写一个类似于内置函数的函数,请使用原型.否则,不要使用原型.
注意:Perl 6将完全改造并且非常有用的原型.这个答案仅适用于Perl 5.
我同意上述两张海报.通常,$
应避免使用.原型中使用块参数(当只有有用&
),水珠(*
),或参考原型(\@
,\$
,\%
,\*
)