Почему некоторые функции в 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 должен иметь книгу верблюдов.