Почему обе версии этого кода не проходят проверку Perl -c? - PullRequest
3 голосов
/ 13 февраля 2010

Метод new для Parse::RecDescent имеет этот прототип:

sub new ($$$)
{
   # code goes here
}

и если я создаю такой объект:

my $parser = Parse::RecDescent->new($grammar);

это создаст парсер, а метод получит 2 параметра "Parse :: RecDescent" и $ грамматику, верно? Если я попытаюсь создать объект вроде:

Parse::RecDescent::new("Parse::RecDescent",$grammar)

это не удастся сказать "Недостаточно аргументов для Parse :: RecDescent :: new", и я понимаю это сообщение. Я только передаю 2 параметра. Однако я не понимаю, почему работает версия со стрелкой.

Вы можете объяснить?

1 Ответ

11 голосов
/ 13 февраля 2010

Прототипы функций не проверяются, когда вы вызываете его как метод в стиле OO. Кроме того, вы обходите проверку прототипа, когда вызываете подпрограмму с помощью &, как в &sub(arg0, arg1..);

С perldoc perlsub :

Форма "&" не только делает список аргументов необязательным, но также отключает любую проверку прототипа на аргументы, которые вы предоставляете. Это отчасти для исторические причины, и частично из-за удобного способа обмана, если вы знаете, что делаете. Смотрите прототипы ниже.

На вызовы методов также не влияют прототипы, поскольку вызываемая функция является неопределенной во время компиляции, поскольку точный вызываемый код зависит от наследования.

Хотя синтаксически правильный Parse::RecDescent::new("Parse::RecDescent", $grammar), это довольно вонючий способ вызова конструктора, и теперь вы заставляете его определяться в этом классе (а не в предке). Если вам действительно нужно проверить свои аргументы, сделайте это внутри метода:

sub new
{
    my ($class, @args) = @_;
    die "Not enough arguments passed to constructor" if @args < 2;
    # ...
}

См. Также этот более ранний вопрос о прототипах и почему они обычно не так уж хороши.

...