Сделайте так, чтобы Perl смотрел вперед для суб-прототипов - PullRequest
0 голосов
/ 30 декабря 2018

Perl слишком простителен: если вы передаете дополнительные аргументы sub s, они просто игнорируются.

Чтобы избежать этого, я хотел бы использовать прототипы, чтобы каждый sub получилправильное количество аргументов.

Это работает нормально, пока я объявляю прототип перед его использованием:

sub mysub($);
sub mysub2($);

mysub(8);
mysub(8,2); # Complain here                                                            

sub mysub($) {
    mysub2($@);
}

sub mysub2($) {
    if($_[0] == 1) {
        mysub(2);
    }
    print $@;
}

Но я действительно ненавижу разделять это.Я бы предпочел, чтобы Perl прочитал полный файл, чтобы увидеть, есть ли объявления ниже.Поэтому я хотел бы написать что-то вроде:

use prototypes_further_down; # This does not work

mysub(8);
mysub(8,2); # Complain here                                                            

sub mysub($) {
    mysub2($@);
}

sub mysub2($) {
    if($_[0] == 1) {
        mysub(2);
    }
    print $@;
}

Могу ли я как-нибудь попросить Perl сделать это?

1 Ответ

0 голосов
/ 30 декабря 2018

Чтобы избежать этого, я бы хотел использовать прототипы, чтобы убедиться, что каждому sub дано правильное количество аргументов.

Нет, вы бы этого не сделали.Несмотря на сходство в названии, прототипы Perl не являются прототипами функций вашего отца.Цитирование Проблема с прототипами (выделено мной),

Прототипы Perl 5 служат двум целям.Во-первых, они намекают парсеру изменить способ, которым он анализирует подпрограммы и их аргументы.Во-вторых, они изменяют способ, которым Perl 5 обрабатывает аргументы этих подпрограмм, когда он их выполняет. Распространенной ошибкой новичка является предположение, что они служат той же языковой цели, что и подпрограммные подписи на других языках.Это не так.

В дополнение к тому, что они не имеют той же цели, обход прототипов является тривиальным, поэтому они не обеспечивают никакой реальной защиты от кого-то, кто намеренно хочет вызвать ваш код в (что вы считаете) "неправильный" путь.Как говорит perldoc perlsub,

Объявление функции должно быть видно во время компиляции.Прототип влияет только на интерпретацию вызовов нового стиля функции, где новый стиль определяется как не использующий символ &.Другими словами, если вы вызываете ее как встроенную функцию, то она ведет себя как встроенная функция.Если вы называете это как старомодная подпрограмма, то она ведет себя как старомодная подпрограмма.Из этого правила естественно вытекает, что прототипы не влияют на ссылки подпрограмм, такие как \&foo, или на косвенные вызовы подпрограмм, такие как &{$subref} или $subref->().

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

Даже если вы можете заставить ее жаловаться на mysub(8,2), &mysub(8,2) или $subref = \&mysub; $subref->(8,2) или (если бы mysub был метод объекта внутри package MyModule) $o = MyModule->new; $o->mysub(8,2) работал бы без жалоб.

Если вы хотите проверить, как ваши подпрограммы вызываются с помощью основного Perl (до 5.20), то вам нужновыполнить проверку самостоятельно в теле подпрограммы.Perl 5.20 и новее имеют («экспериментальный» на момент написания этой статьи) Signatures расширение для вложенных объявлений, которые могут работать в ваших целях, но я никогда не использовал его сам, поэтому не могу говоритьк его эффективности или ограничениям.Есть также много CPAN модулей, доступных для обработки такого рода вещей, которые вы можете найти, выполнив поиск таких вещей, как «подпись» или «прототип».

Независимо от выбранного вами подхода,вы не сможете получить ошибки времени компиляции о неправильных сигнатурах функций, если не определите эти сигнатуры до их использования.В таких случаях, как ваш пример, когда две подпрограммы взаимно вызывают друг друга, это можно сделать, используя предварительное объявление, чтобы заранее установить свою подпись:

sub mysub($foo);                               # Forward declaration
sub mysub2 { mysub(8) }
sub mysub  { mysub2('infinite loops ftw!') }   # Complete version of the code
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...