2016-12-12 6 views
5

Представьте, что я хочу загрузить модуль во время выполнения. Я ожидал, что это работаетНевозможно загрузить `Cwd` (и другие непрофильные модули) во время выполнения

use warnings; 
use strict; 

eval { 
    require Cwd; 
    Cwd->import; 
}; 
if ([email protected]) { die "Can't load Cwd: [email protected]" } 

say "Dir: ", getcwd; 

, но это не делает, за Bareword "getcwd" not allowed ....

Cwd экспорт getcwd по умолчанию. Я попробовал присвоить именам функций import, и я попытался с другими функциями. Он работает с полным именем, say Cwd::getcwd, поэтому я думаю, что он не импортирует.

Это работает как попытку несколько других основных модулей, которые я пробовал, например

use warnings; 
use strict; 

eval { 
    require List::Util; 
    List::Util->import('max'); 
}; 
if ([email protected]) { die "Can't load List::Util: [email protected]" } 

my $max = max (1, 14, 3, 26, 2); 
print "Max is $max\n"; 

Примечание добавило   Видимо, вызовы функций с скобкой дать ключ к компилятору. Однако, по-моему, вопрос остается, см. EDIT в конце. Кроме того, функция, подобная first BLOCK LIST из модуля выше, не работает.


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

Я могу представить, что используемый символ (функция) неизвестен во время компиляции, если во время выполнения используется require, но он работает для (других) базовых модулей. Я думал, что это стандартный способ загрузки во время выполнения.

Если мне нужно использовать полные имена при динамической загрузке, то в порядке, но что это за непоследовательность? И как do Я загружаю (и использую) неосновные модули во время выполнения?

Я также пробовал с Module::Load::Conditional, и это не сработало.

Что мне не хватает, и как загружать модули во время выполнения?   (Пробовал с 5.16 и 5.10.1.)


EDIT

Как отметил Matt Jacob, вызов с скобка работ, getcwd(). Однако, учитывая perlsub

NAME LIST; # Скобки необязательны, если предопределенные/импорта.

Это подразумевает, что импорт не работал, и вопрос о том, почему остается.

Кроме того, использование разнообразного синтаксиса в зависимости от того, как загружен модуль, не очень хорошо. Кроме того, я не могу заставить непрофильные модули работать таким образом, особенно те, которые имеют синтаксис, например List::MoreUtils.

+2

Perl не знает, что это подпрограмма. Вам нужно: '& getcwd' (не очень),' использовать subs qw (getcwd); '(лучше) или просто' getcwd() '(лучший). –

+0

@MattJacob спасибо, это делает работа. Однако вопрос остается, как поясняется в примечании, которое я добавил в конце. – zdim

+0

Импорт еще не работал с момента компиляции вызова getcwd, поэтому вы получаете строгую ошибку (или без строгой интерпретации, интерпретируете ее как строку «getcwd»). Добавление скобок говорит perl, что это подзаголовок, а не простое слово. – ysth

ответ

4

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


eval { 
    require Cwd; 
    Cwd->import; 
}; 
if ([email protected]) { die "Can't load Cwd: [email protected]" } 

say "Dir: ", getcwd; 

Во время компиляции, нет в таблице символов main:: не getcwd. Без каких-либо намеков указать, что это функция (getcwd() или &getcwd), синтаксический анализатор не знает, и strict жалуется.


eval { 
    require List::Util; 
    List::Util->import('max'); 
}; 
if ([email protected]) { die "Can't load List::Util: [email protected]" } 

my $max = max (1, 14, 3, 26, 2); 

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

В обоих случаях проверка strict происходит до того, как import когда-либо называется.

Список :: MoreUtils является особенным, потому что функции используют прототипы. Прототипы игнорируются, если определение функции не отображается во время компиляции. Таким образом, вы не только должны дать анализатору подсказку, что вы вызываете функцию, вы должны назвать его по-разному, так как прототип будет проигнорировано:

use strict; 
use warnings 'all'; 
use 5.010; 

eval { 
    require List::MoreUtils; 
    List::MoreUtils->import('any') 
}; 
die "Can't load List::MoreUtils: [email protected]" if [email protected]; 

say 'found' if any(sub { $_ > 5 }, 1..9); 
+0

Большое спасибо. Поэтому нужно подумать о компиляторе и использовать другой синтаксис при загрузке во время выполнения. Это хорошо знать. (Я видел это много раз и никогда не видел намека на это.) – zdim

+0

Я думал о том, что символы не известны, как указано в вопросе, но тогда мое восприятие, что оно «работало» для других модулей, заставило меня поверить, что некоторые магия делалась (для основных модулей, я думал). – zdim

+0

Вы должны думать о синтаксическом анализаторе даже в других ситуациях, например. 'sub foo {...} foo;' все в порядке, но 'foo; sub foo {...} 'нет. Поэтому некоторые люди всегда используют круглые скобки; это просто слишком легко укусить. И это еще один пример того, почему вам следует избегать прототипов. – ThisSuitIsBlackNot