Почему круглые скобки необязательны только после вложенной декларации?
5388 просмотра
4 ответа
(Предположим на use strict; use warnings;
протяжении всего этого вопроса.)
Я изучаю использование sub
.
sub bb { print @_; }
bb 'a';
Это работает как ожидалось. Скобки необязательны, как и многие другие функции, например, и print, open
т. Д.
Тем не менее, это вызывает ошибку компиляции:
bb 'a';
sub bb { print @_; }
String found where operator expected at t13.pl line 4, near "bb 'a'"
(Do you need to predeclare bb?)
syntax error at t13.pl line 4, near "bb 'a'"
Execution of t13.pl aborted due to compilation errors.
Но это не так:
bb('a');
sub bb { print @_; }
Аналогично, саб без аргументов, таких как:
special_print;
my special_print { print $some_stuff }
Вызовет эту ошибку:
Bareword "special_print" not allowed while "strict subs" in use at t13.pl line 6.
Execution of t13.pl aborted due to compilation errors.
Способы устранения этой конкретной ошибки:
- Поставьте & перед именем, например
&special_print
- Поставьте пустую скобку после имени, например
special_print()
- Predeclare
special_print
сsub special_print
в верхней части сценария. - Позвоните
special_print
после под декларации.
У меня вопрос, почему это специальное лечение? Если я могу использовать подпрограмму глобально в скрипте, почему я не могу использовать ее так, как мне хочется? Есть ли логика для sub
реализации таким образом?
ЭТА: Я знаю, как я могу это исправить. Я хочу знать логику этого.
Автор: TLP Источник Размещён: 13.11.2019 11:34Ответы (4)
33 плюса
Я думаю, что вам не хватает того, что Perl использует строго однопроходный парсер. Он не сканирует файл на наличие подпрограмм, а затем возвращается и компилирует все остальное. Зная это, ниже описано, как работает система однопроходного анализа:
В Perl sub NAME
синтаксис объявления подпрограммы эквивалентен следующему:
sub name {...} === BEGIN {*name = sub {...}}
Это означает, что sub NAME
синтаксис имеет эффект времени компиляции. Когда Perl анализирует исходный код, он работает с текущим набором объявлений. По умолчанию набор встроенных функций. Поскольку Perl уже знает об этом, он позволяет опустить круглые скобки.
Как только компилятор достигает блока BEGIN, он компилирует внутреннюю часть блока, используя текущий набор правил, а затем немедленно выполняет блок. Если что-либо в этом блоке изменит набор правил (например, добавление подпрограммы в текущее пространство имен), эти новые правила будут действовать до конца анализа.
Без предварительно объявленного правила идентификатор будет интерпретироваться следующим образом:
bareword === 'bareword' # a string
bareword LIST === syntax error, missing ','
bareword() === &bareword() # runtime execution of &bareword
&bareword === &bareword # same
&bareword() === &bareword() # same
При использовании строгих правил и предупреждений, как вы указали, голые слова не будут преобразованы в строки, поэтому первый пример - это синтаксическая ошибка.
Если предварительно объявлено любое из следующего:
sub bareword;
use subs 'bareword';
sub bareword {...}
BEGIN {*bareword = sub {...}}
Тогда идентификатор будет интерпретироваться следующим образом:
bareword === &bareword() # compile time binding to &bareword
bareword LIST === &bareword(LIST) # same
bareword() === &bareword() # same
&bareword === &bareword # same
&bareword() === &bareword() # same
Таким образом, чтобы первый пример не был синтаксической ошибкой, одно из предшествующих объявлений подпрограммы должно быть просмотрено первым.
Что касается того, что стоит за всем этим, у Perl много наследства. Одной из целей разработки Perl была полная обратная совместимость. Скрипт, который работает в Perl 1, все еще работает в Perl 5. Из-за этого невозможно изменить правила, связанные с анализом голых слов.
Тем не менее, вам будет трудно найти язык, который будет более гибким в способах вызова подпрограмм. Это позволяет вам найти метод, который лучше всего подходит для вас. В моем собственном коде, если мне нужно вызвать подпрограмму до того, как она была объявлена, я обычно использую name(...)
, но если у этой подпрограммы есть прототип, я назову ее как &name(...)
(и вы получите предупреждение), вызываемая слишком рано, чтобы проверить прототип «Если вы не называете это так).
17 плюса
Лучший ответ, который я могу придумать, это то, как написан Perl. Это не удовлетворительный ответ, но, в конце концов, это правда. Perl 6 (если он когда-либо выйдет) не будет иметь этого ограничения.
В Perl много грубого и грубого из пяти разных версий языка. Perl 4 и Perl 5 внесли некоторые существенные изменения, которые могут вызвать проблемы с более ранними программами, написанными свободно.
Из-за долгой истории и различных способов, которыми Perl имеет и может работать, Perl может быть трудно понять, что происходит. Когда у вас есть это:
b $a, $c;
В Perl нет способа узнать, является ли b строкой и является ли просто голым словом (что было разрешено в Perl 4) или b является функцией. Если b - функция, она должна быть сохранена в таблице символов, так как остальная часть программы анализируется. Если b не подпрограмма, вы не должны помещать ее в таблицу символов.
Когда Perl-компилятор видит это:
b($a, $c);
Он не знает, что делает функция b , но, по крайней мере, знает, что это функция, и может сохранить ее в таблице символов, ожидая, когда определение придет позже.
Когда вы предварительно объявляете свою функцию, Perl может видеть это:
sub b; #Or use subs qw(b); will also work.
b $a, $c;
и знать, что b является функцией. Возможно, он не знает, что делает функция, но теперь есть запись в таблице символов для b как функции.
Одна из причин для Perl 6 состоит в том, чтобы удалить большую часть багажа, оставшегося от старых версий Perl, и удалить странные вещи, подобные этой.
Кстати, никогда не используйте прототипы Perl, чтобы обойти это ограничение. Используйте use subs
или предварительно объявите пустую подпрограмму. Не используйте прототипы.
6 плюса
Круглые скобки являются необязательными, только если подпрограмма была предварительно объявлена. Это задокументировано в perlsub .
Perl должен знать во время компиляции, является ли голое слово именем подпрограммы или строковым литералом. Если вы используете круглые скобки, Perl будет догадываться, что это имя подпрограммы. В противном случае вам необходимо предоставить эту информацию заранее (например, используя subs
).
-2 плюса
Причина в том, что Ларри Уолл - лингвист, а не ученый.
Ученый-компьютерщик : грамматика языка должна быть максимально простой и понятной.
- Избегает сложности в компиляторе
- Устраняет источники двусмысленности
Ларри Уолл : Люди работают не так, как компиляторы. Язык должен служить программисту, а не компилятору. Смотрите также план Ларри Уолла о трех достоинствах программиста .
Автор: edgar.holleis Размещён: 13.05.2011 02:24Вопросы из категории :
- perl Как определить, имеет ли переменная число в Perl?
- perl Как я могу проверить STDIN без блокировки в Perl?
- perl Как выполнить подстановку Perl для строки, сохранив оригинал?
- perl Какой самый простой способ установить отсутствующий модуль Perl?
- perl Что происходит с Perl 6?
- perl Как запустить интерактивную консоль для Perl?
- perl Как я могу создать XML из Perl?
- perl Какой лучший движок XSLT для Perl?
- perl Что "select ((select (s), $ | = 1) [0])" делает в Perl?
- perl Как я могу получить длину строки в Perl?
- perl Как получить список стеков вызовов в Perl?
- perl How can I check if I have a Perl module before using it?
- perl Как я могу использовать новый модуль Perl без разрешения на установку?
- perl Есть ли в Perl PHP-подобные динамические переменные?
- perl Что делает shift () в Perl?
- perl Почему прототипы функций Perl 5 плохие?
- perl Как объединить хэши в Perl?
- perl Как я могу получить букву диска в Perl?
- perl Как использовать переменную на стороне замены оператора подстановки Perl?
- perl Вы предпочитаете "if (var)" или "if (var! = 0)"?