2013-12-05 3 views
7

Кто-то имеет представление о том, чтобы использовать переменную массива вместо массива (списка) буквального, в use функции заявления о, например:Perl: Использование модуля @list

my @list = qw(foo zoo); 
use Module @list; 

вместо

use Module qw(foo zoo); 

так что она пишет, например:

my @consts = qw(PF_INET PF_INET6); 
use Socket @consts; 
printf "%d, %d\n", PF_INET, PF_INET6; 

, который, казалось бы, работает, как ожидалось:

2, 10

Затем она делает это с каким-либо другим модулем, например, Time::HiRes. Вместо

use Time::HiRes qw(CLOCK_REALTIME CLOCK_MONOTONIC); 
printf "%d, %d\n", CLOCK_REALTIME, CLOCK_MONOTONIC; 

0, 1

она делает:

my @consts = qw(CLOCK_REALTIME CLOCK_MONOTONIC); 
use Time::HiRes @consts; 
printf "%d, %d\n", CLOCK_REALTIME, CLOCK_MONOTONIC; 

0, 0

Он вдруг не работает, как он работал с Socket модуль! Здесь что-то плохое.

(.. это в нестрогой среде Если она использовала use strict, она бы даже получила ошибку С другой стороны, она не получает никакого намека на все в своем первом, казалось бы, рабочим пример -.., Даже если она имеет use strict; use warnings; use diagnostics там.)

Теперь она хочет изучить это странное поведение. Пытается импортирующие пустой список:

my @consts =(); 
use Socket @consts; 
printf "%d, %d\n", PF_INET, PF_INET6; 

2, 10

удивительно работает так же, в то время как он, вероятно, не стоит, как:

use Socket(); 
printf "%d, %d\n", PF_INET, PF_INET6; 

0, 0

Затем она немного копается в этих модулях и понимает, что разница между этими двумя модулями заключается в том, что эти константы не равны @EXPORT ed соответственно.

Ее вывод в том, что use Module @list не работает, как она ожидает.

Что было бы лучшим объяснением этого? Что она делает неправильно - Каков правильный способ использования предварительно определенного массива в инструкции use?

+0

Re "Tries импорт пустого списка ... на удивление работает также", Почему? 'use foo @foo;' не отличается от 'use foo;'. Оба предоставляют пустой список.'use foo();' также будет передавать пустой список, но это специальный * синтаксис *. – ikegami

ответ

19

Это связано с тем, когда код выполнен.use выполняется во время компиляции, а my @list выполняется только во время выполнения. Таким образом, в массиве нет точки, в которую загружен модуль.

Модуль Socket exportsPF_INET и PF_INET6 по умолчанию, так что это не имеет значения, если вы поместите его в use линии. Но Time :: HiRes does not export stuff по умолчанию.

Ошибка вы получаете с strict является:

Bareword «CLOCK_REALTIME» не допускается в то время как «строгой подлодки» в использовании ...

Это говорит о том, что Perl не знает, что CLOCK_REALTIME является подпрограммой, правда, потому что он не был загружен, когда мы делаем это:

my @consts = qw(CLOCK_REALTIME CLOCK_MONOTONIC); 
use Time::HiRes @consts; 
printf "%d, %d\n", CLOCK_REALTIME, CLOCK_MONOTONIC; 

What use does является require и import СПИСОК аргументов во время компиляции. Так что это так же, как:

BEGIN { 
    require foo; 
    foo->import(); 
} 

Зная это, мы можем сделать это сами:

use strict; use warnings; 
BEGIN { 
    my @consts = qw(CLOCK_REALTIME CLOCK_MONOTONIC); 
    require Time::HiRes; 
    Time::HiRes->import(@consts); 
} 

printf "%d, %d\n", CLOCK_REALTIME, CLOCK_MONOTONIC; 

__END__ 
0, 1 

, как это будет работать, так как массив @const определяется в том же объеме и уже доступны при интерпретатор Perl выполняет его.

Из-за видимости, просто добавив BEGIN блок перед использованием будет не работа.

BEGIN { 
    my @consts = qw(CLOCK_REALTIME CLOCK_MONOTONIC); 
} 

use Time::HiRes (@consts); 

Вы можете обойти эту проблему, объявив переменную вне BEGIN блока. Таким образом, он будет доступен в следующем блоке блока , и значение уже будет установлено, поскольку BEGIN blocks are executed at compile time in FIFO order.

my @consts; 
BEGIN { 
    @consts = qw(CLOCK_REALTIME CLOCK_MONOTONIC); 
} 

use Time::HiRes (@consts); 
printf "%d, %d\n", CLOCK_REALTIME, CLOCK_MONOTONIC; 

__END__ 
0, 1 

Подведем итоги:

  • это из-за двух вещей: область применения и порядок исполнения
  • тот факт, что вы передаете массив не проблема здесь - массив будет part of the LIST, который передается
  • если вы не use strict, вы не можете легко найти проблему
  • если добавить BEGIN блок перед use и поместите my декларацию вне BEGIN, она работает
  • если взять require вместо use и import себя, вы также можете передать массив
+0

Излишне отстаивать «не строгую». Исправлена. – ikegami

+0

Вы также можете использовать 'foo do {my @syms = ...; ...; @syms; }; ' – ikegami

+0

Очень приятно. Забавно, что она недовольна, потому что она finnaly хотела сделать: 'printf '% d,% d \ n", @ consts', что, очевидно, неверно. Или, не импортируя, это также также не работает с ее помощью: 'print Time :: HiRes :: $ consts [0]'. Как она может использовать строку как символ? – mykhal

Смежные вопросы