Почему обе версии этого кода не проходят проверку Perl -c?
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 ответ
Прототипы функций не проверяются, когда вы вызываете его как метод в стиле 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;
# ...
}
Смотрите также этот предыдущий вопрос о прототипах и почему они обычно не так уж хороши.