Как уже упоминалось в другом ответе, $$
объявляет прототип. Другой ответ не говорит о том, для чего нужны прототипы. Они не для проверки ввода, они являются подсказками для синтаксического анализатора.
Представьте, что у вас есть две функции, объявленные как:
sub foo($) { ... }
sub bar($$) { ... }
Теперь, когда вы пишете что-то неоднозначное, например:
foo bar 1, 2
Перл знает, где положить паренс; Бар занимает два аргумента, поэтому он потребляет два ближайших к нему. foo принимает один аргумент, поэтому он берет результат bar и два аргумента:
foo(bar(1,2))
Другой пример:
bar foo 2, 3
То же самое относится; foo берет один аргумент, поэтому он получает 2. столбец принимает два аргумента, поэтому он получает foo(2)
и 3:
bar(foo(2),3)
Это довольно важная часть Perl, поэтому игнорирование ее как «никогда не использовать» приносит вам медвежью услугу. Почти каждая внутренняя функция использует прототипы, поэтому, понимая, как они работают в вашем собственном коде, вы можете лучше понять, как они используются встроенными функциями. Тогда вы можете избежать ненужных скобок, что делает код более приятным.
Наконец, один анти-шаблон, против которого я вас предупрежу:
package Class;
sub new ($$) { bless $_[1] }
sub method ($) { $_[0]->{whatever} }
Когда вы вызываете код как методы (Class->method
или $instance->method
), проверка прототипа совершенно бессмысленна. Если ваш код может быть вызван только как метод, добавление прототипа является неправильным. Я видел некоторые популярные модули, которые делают это (привет, XML::Compile
), но это неправильно, поэтому не делайте этого. Если вы хотите задокументировать, сколько аргументов нужно передать, как насчет:
sub foo {
my ($self, $a, $b) = @_; # $a and $b are the bars to fooify
....
или
use MooseX::Method::Signatures;
method foo(Bar $a, Bar $b) { # fooify the bars
....
В отличие от foo($$)
, они значимы и читабельны.