Почему обе версии этого кода не проходят проверку -c Perl?

StackOverflow https://stackoverflow.com/questions/2255495

  •  20-09-2019
  •  | 
  •  

Вопрос

В new способ Parse::RecDescent имеет этот прототип:

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

и если я создам такой объект, как этот:

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

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

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

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

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

Это было полезно?

Решение

Прототипы функции не проверяются, когда вы вызываете ее как метод в стиле OO.Кроме того, вы обходите проверку прототипа при вызове sub с помощью &, как в &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;
    # ...
}

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top