有人想在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
语句中使用预定义数组的正确方法是什么?
这与代码执行时有关。 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
,你也可以传递一个数组