Почему некоторые функции в Perl должны быть вызваны с помощью parens, а другие - нет?
Пример для иллюстрации - это синопсис моего собственного Test::Version
.
use Test::More;
use Test::Version 0.04;
# test blib or lib by default
version_all_ok();
done_testing;
Мне не нужно включать скобки на done_testing();
Я могу просто назвать это. Однако, когда я попытался вызвать version_all_ok;
(обратите внимание: первая попытка в Dist:: Zilla:: Plugin:: Test:: Version завершилась с ошибкой) Я получаю сообщение об ошибке. Почему это?
Обновление Возможно, мой пример не так хорош, как я думал. Фактическая ошибка, которую я получил, -
Bareword "version_all_ok" not allowed while "strict subs" in use at t/release-test-version.t line 19.
и здесь полный код
#!/usr/bin/perl
BEGIN {
unless ($ENV{RELEASE_TESTING}) {
require Test::More;
Test::More::plan(skip_all => 'these tests are for release candidate testing');
}
}
use 5.006;
use strict;
use warnings;
use Test::More;
eval "use Test::Version";
plan skip_all => "Test::Version required for testing versions"
if [email protected];
version_all_ok; # of course line 19, and version_all_ok() works here.
done_testing;
Ниже приведены соответствующие фрагменты, извлеченные из Test::Version 1.0.0
для экспорта.
use parent 'Exporter';
our @EXPORT = qw( version_all_ok ); ## no critic (Modules::ProhibitAutomaticExportation)
our @EXPORT_OK = qw( version_ok );
Ответы
Ответ 1
В сущности, потому, что Perl должен знать, что одно слово означает вызов функции, чтобы разобрать его как вызов функции. Перл может изучить этот интересный факт:
-
Возможно, вы украсили одно слово как вызов функции, добавив &
или ->
или добавив (...)
или и то, и другое. Perl будет доверять тому, что вы знаете, о чем говорите, и анализируете его как вызов функции, даже если он еще не знает, какую функцию он должен будет вызывать.
-
Вы могли бы объявить функцию с этим именем, прежде чем Perl попытается разобрать вызов. Обычно, use
-используя модуль, достаточно, чтобы символы создавались в нужное время; вы делаете что-то не так в Test::Version
, чтобы символ не экспортировался до тех пор, пока он не понадобится для компиляции теста script.
В вашем коде вы оберните use
внутри eval
, что фактически задерживает его до времени выполнения. Следовательно, символ version_all_ok
недоступен, когда Perl пытается скомпилировать вызов, и он взрывается. Принудительное компиляцию eval
должно быть достаточным для того, чтобы сделать символ доступным:
BEGIN {
eval "use Test::Version";
plan skip_all => "Test::Version required for testing versions"
if [email protected];
}
Ответ 2
В этом примере показано (очевидно, я думаю), что все, что вам нужно, это предустановить функцию.
#!/usr/bin/env perl
use strict;
use warnings;
sub hi {
print "hi\n";
}
hi; #could be `hi();`
bye(); #could not be `bye;`
sub bye {
print "bye\n";
}
Если ваша чувствительность требует, чтобы вы определили свои подпрограммы внизу, но вы хотите, чтобы их вызывали без парнеров (как если бы они были предопределены), вы можете использовать subs
прагма:
#!/usr/bin/env perl
use strict;
use warnings;
use subs qw/hi bye/;
hi;
bye;
sub hi {
print "hi\n";
}
sub bye {
print "bye\n";
}
UPDATE:
Похоже, что прагма subs
может даже облегчить проблемы из строковых оценок. Вы можете попробовать use subs 'version_all_ok';
в верхней части вашего script. Мое доказательство концепции:
#!/usr/bin/env perl
use strict;
use warnings;
use subs qw/hi bye/;
eval <<'DECLARE';
sub bye {
print "bye\n";
}
DECLARE
hi;
bye;
sub hi {
print "hi\n";
}
Ответ 3
Я не могу дублировать это, используя Test:: Version 1.0.0 или 0.04. Возможно ли, что вы не экспортировали то, что считали себя?
Можете ли вы дважды проверить и предоставить как полный script, который был неудачным, сообщение об ошибке, так и полное script, что удалось, и версию perl, которую вы используете?
Обновление: нормально, вы загружаете Test:: Version во время выполнения; это означает, что когда version_all_ok
встречается во время компиляции, такой подпрограммы не существует. Нет никакого способа обойти это без какого-либо изменения теста script, например:
my $has_test_version;
BEGIN { $has_test_version = eval "use Test::Version; 1" }
plan skip_all => "Test::Version required for testing versions" if ! $has_test_version;
Ответ 4
Он просто должен быть объявлен перед вашим использованием, все еще используя круглые скобки или амперсанд, должен использоваться для различения и ясности.
Ответ 5
Это разрешено, если функция была объявлена ранее, и она будет рассматриваться как оператор списка (ПРЕДУПРЕЖДЕНИЕ: это может изменить приоритет оператора!)
Ответ 6
От Программирование Perl, глава 29 Функции:
Предопределенные функции Perl могут использоваться либо с круглыми скобками, либо без них вокруг своих аргументов; синтаксические сводки в этой главе опускают круглые скобки. Если вы используете круглые скобки, простым, но иногда неожиданным правилом является следующее: если он выглядит как функция, то это функция, поэтому приоритет не имеет значения. В противном случае это оператор списка или унарный оператор, и приоритет имеет значение. Будьте осторожны, потому что даже если вы помещаете пробел между ключевым словом и его левой скобкой, это не мешает ему быть функцией
Найдено на стр .677 (отсутствует онлайн в Google Books из-за авторских прав) - каждый программист Perl должен иметь книгу верблюдов.