I have been using Perl for some time, but today I开发者_开发技巧 came across this code:
sub function1($$)
{
//snip
}
What does this mean in Perl?
It is a function with a prototype that takes two scalar arguments.
There are strong arguments for not actually using Perl prototypes in general - as noted in the comments below. The strongest argument is probably:
- Far More Than Everything You've Ever Wanted to Know about Prototypes in Perl
There's a discussion on StackOverflow from 2008:
- SO 297034
There's a possible replacement in the MooseX::Method::Signatures module.
As the other answer mentions, the $$
declares a prototype. What the other answer doesn't say is what prototypes are for. They are not for input validation, they are hints for the parser.
Imagine you have two functions declared like:
sub foo($) { ... }
sub bar($$) { ... }
Now when you write something ambiguous, like:
foo bar 1, 2
Perl knows where to put the parens; bar takes two args, so it consumes the two closest to it. foo takes one arg, so it takes the result of bar and the two args:
foo(bar(1,2))
Another example:
bar foo 2, 3
The same applies; foo takes one arg, so it gets the 2. bar takes two args, so it gets foo(2)
and 3:
bar(foo(2),3)
This is a pretty important part of Perl, so dismissing it as "never use" is doing you a disservice. Nearly every internal function uses prototypes, so by understanding how they work in your own code, you can get a better understanding of how they're used by the builtins. Then you can avoid unnecessary parentheses, which makes for more pleasant-looking code.
Finally, one anti-pattern I will warn you against:
package Class;
sub new ($$) { bless $_[1] }
sub method ($) { $_[0]->{whatever} }
When you are calling code as methods (Class->method
or $instance->method
), the prototype check is completely meaningless. If your code can only be called as a method, adding a prototype is wrong. I have seen some popular modules that do this (hello, XML::Compile
), but it's wrong, so don't do it. If you want to document how many args to pass, how about:
sub foo {
my ($self, $a, $b) = @_; # $a and $b are the bars to fooify
....
or
use MooseX::Method::Signatures;
method foo(Bar $a, Bar $b) { # fooify the bars
....
Unlike foo($$)
, these are meaningful and readable.
精彩评论