Почему некоторые функции в Perl должны вызываться с паренсом, а другие нет? - PullRequest
10 голосов
/ 22 июля 2011

Примером для иллюстрации является мой собственный 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 $@;

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 );

Ответы [ 6 ]

15 голосов
/ 22 июля 2011

Фундаментально, потому что Perl должен знать, что голое слово означает вызов функции, чтобы проанализировать его как вызов функции. Perl может узнать этот интересный факт двумя способами:

  1. Вы могли бы оформить голое слово как вызов функции, добавив & или -> или добавив (...) или оба. Perl будет верить, что вы знаете, о чем говорите, и анализировать голое слово как вызов функции, даже если он еще не знает, какую функцию ему придется вызывать.

  2. Возможно, вы объявили функцию с таким именем до того, как Perl попытается проанализировать вызов. Обычно, use -ing модуля достаточно, чтобы обеспечить создание символов в нужное время; вы делаете что-то не так в Test::Version, так что символ не экспортируется до тех пор, пока он не понадобится для компиляции тестового сценария.

В своем коде вы заключаете use в eval, что эффективно задерживает его до времени выполнения. Следовательно, символ version_all_ok недоступен, когда Perl пытается скомпилировать вызов и он взрывается. Чтобы сделать символ доступным, достаточно eval времени для компиляции:

BEGIN {
    eval "use Test::Version";
    plan skip_all => "Test::Version required for testing versions"
        if $@;
}
4 голосов
/ 22 июля 2011

Этот пример показывает (ясно, что я думаю), что все, что вам нужно, это предварительно объявить функцию.

#!/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";
}

ОБНОВЛЕНИЕ: может показаться, что прагма subs может даже облегчить проблемы, связанные с пропусками строк,Вы можете попробовать use subs 'version_all_ok'; в верхней части вашего скрипта.Мое доказательство концепции:

#!/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";
}
2 голосов
/ 22 июля 2011

Я не могу продублировать это, используя Test :: Version 1.0.0 или 0.04. Возможно, вы не экспортировали то, что думали?

Можете ли вы перепроверить и предоставить полный сценарий, который дал сбой, сообщение об ошибке, полный сценарий, который был выполнен успешно, и используемую вами версию perl?

Обновление: хорошо, вы загружаете Test :: Version во время выполнения; это означает, что когда version_all_ok встречается во время компиляции, такой подпрограммы нет. Нет никакого способа обойти это без изменения сценария тестирования, например:

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;
0 голосов
/ 22 июля 2011

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

0 голосов
/ 22 июля 2011

С Программирование на Perl , глава 29 Функции :

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

Найдено на стр.677 (отсутствует в Интернете по адресу Google Книги из-за авторских прав) - у каждого программиста Perl должна быть книга верблюдов.

0 голосов
/ 22 июля 2011

Это разрешено, если функция была объявлена ​​ранее, и она будет рассматриваться как оператор списка (ВНИМАНИЕ: это может изменить приоритет оператора!)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...