有人想在use
函数语句中使用数组变量代替数组(列表)文字,如:
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 :(得分:19)
这与代码执行时有关。 use
在编译时执行,而my @list
仅在运行时执行。因此,数组不存在于模块加载的位置。
模块Socket exports PF_INET
和PF_INET6
默认情况下,如果您将其放在use
行中并不重要。但默认情况下,Time :: HiRes does not export stuff。
strict
出现的错误是:
使用“严格潜艇”时不允许使用Bareword“CLOCK_REALTIME”......
这告诉我们Perl不知道CLOCK_REALTIME
是一个sub,这是真的,因为当我们这样做时它没有被加载:
my @consts = qw(CLOCK_REALTIME CLOCK_MONOTONIC);
use Time::HiRes @consts;
printf "%d, %d\n", CLOCK_REALTIME, CLOCK_MONOTONIC;
What use
does是require
模块,import
是编译时参数的LIST。所以它与:
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
块的范围内可用,并且因为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
所以回顾一下:
use strict
,则无法轻易找到问题BEGIN
前面添加use
块并将my
声明置于BEGIN
之外,则可以require
代替use
和import
,您也可以传递数组