Как импортировать константу с помощью «использовать строгий», избегая «Не могу использовать голое слово ... в качестве ссылки на массив» - PullRequest
4 голосов
/ 07 марта 2019

У меня есть модуль в файле, который экспортирует константу, которая является ссылкой на массив. Я могу использовать эту константу внутри определяющего модуля, но не могу использовать ее после импорта. Сообщение об ошибке говорит Can't use bareword ("AR") as an ARRAY ref while "strict refs" in use at mod.pl line 28..

Рассмотрим этот демонстрационный код:

#!/usr/bin/perl
require 5.018_000;

use warnings;
use strict;

package Test;

use warnings;
use strict;

BEGIN {
    require Exporter;
    our $VERSION = 1.00;                # for version checking
    # Inherit from Exporter to export functions and variables
    our @ISA = qw(Exporter);
    our @EXPORT = qw();                 # exported by default
    our @EXPORT_OK = qw(AR);            # can be optionally exported
}

use constant AR => [1,2,3];

print AR->[1], "\n";
1;

package main;
Test->import(qw(AR));
print AR->[1], "\n";
#Can't use bareword ("AR") as an ARRAY ref while "strict refs" in use at mod.pl line 28.

Как я могу это исправить?

Ответы [ 3 ]

4 голосов
/ 07 марта 2019

Вам нужно выполнить import, прежде чем ссылка на константу будет скомпилирована.

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

Подход состоит в следующем:

  1. Поместите весь модуль как есть в блок BEGINв начале сценария.
  2. Заменить завершающий 1; на $INC{"Foo/Bar.pm"} = 1; (для Foo::Bar).

Вот и все.Это позволяет вам use модуль как обычно.

Так что, если ваш модуль имеет следующий вид:

package Test;

use strict;
use warnings;

use Exporter qw( import );

our $VERSION = 1.00;
our @EXPORT_OK = qw(AR);

use constant AR => [1,2,3];

1;

И если ваш скрипт следующий:

#!/usr/bin/perl
use 5.018;
use warnings;

use Test qw( AR );

say AR->[1];

Вы можете использовать следующее:

#!/usr/bin/perl

BEGIN {
    package Test;

    use strict;
    use warnings;

    use Exporter qw( import );

    our $VERSION = 1.00;
    our @EXPORT_OK = qw(AR);

    use constant AR => [1,2,3];

    $INC{__PACKAGE__ .'.pm'} = 1;  # Tell Perl the module is already loaded.
}

use 5.018;
use warnings;

use Test qw( AR );

say AR->[1];

Как видите, я сделал некоторые очистки.В частности,

  • Если вам требуется 5.18, возможно, также включите предоставляемые языковые функции.Это было сделано путем замены required 5.018; на use 5.018;
    • Нам не нужно явно использовать use strict;, потому что use 5.012; и более высокие стриктуры включения.
    • Мы можем использовать sayпотому что use 5.010; включает его.
  • Тест не является экспортером, поэтому он не должен наследоваться от экспортера.В течение последних 15-20 лет Exporter предоставляет лучший интерфейс, чем тот, который вы использовали.
  • Нет необходимости создавать или инициализировать @EXPORT, если он вам не нужен.
  • Нет необходимости в блоке BEGIN для инициализации @ISA и @EXPORT_OK.
3 голосов
/ 07 марта 2019

Оператор print AR->[1] анализируется во время компиляции, но константа AR не импортируется в пространство имен main до времени выполнения.

Исправление заключается в том, чтобы гарантировать, что AR будет импортированв main во время компиляции

BEGIN { Test->import( qw(AR) ) }

Есть также обходные пути во время выполнения

print &AR->[1], "\n";
print AR()->[1], "\n";
1 голос
/ 07 марта 2019

я изменил

BEGIN {
    require Exporter;
    our $VERSION = 1.00;                # for version checking
    # Inherit from Exporter to export functions and variables
    our @ISA = qw(Exporter);
    our @EXPORT = qw();                 # exported by default
    our @EXPORT_OK = qw(AR);            # can be optionally exported
}

до

# Inherit from Exporter to export functions and variables
use parent 'Exporter';
our $VERSION = 1.00;                # for version checking
our @EXPORT = qw();                 # exported by default
our @EXPORT_OK = qw(AR);            # can be optionally exported

и ваш код теперь работает

Я подозреваю, что в Exporter есть какой-то код, который должен быть запущен перед настройкой @EXPORT_OK переменной

...