- 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
然后,她正在使用其他模块,例如时间::高分辨率.代替
- use Time::HiRes qw(CLOCK_REALTIME CLOCK_MONOTONIC);
- printf "%d,CLOCK_REALTIME,CLOCK_MONOTONIC;
0,1
她这样做:
- my @consts = qw(CLOCK_REALTIME CLOCK_MONOTONIC);
- use Time::HiRes @consts;
- printf "%d,0
它突然不起作用,就像它与Socket模块一起工作!
这里发生了一件坏事.(..它是在非严格的环境中.如果她使用严格,她甚至会出错.另一方面,她在她的第一个看似有效的例子中没有任何暗示 – 即使她严格使用;使用警告;在那里使用诊断.)
现在她想探索这种奇怪的行为.尝试导入空列表:
my @consts = ();
use Socket @consts;
printf "%d,PF_INET6;2,10
令人惊讶地工作,虽然它可能不应该,如:
use Socket (); printf "%d,PF_INET6;0,0
然后她稍微深入了解这些模块,并意识到两个模块之间的区别在于这些常量分别是@EXPORTed.
她的结论是使用Module @list不能像她期望的那样工作.
对此最好的解释是什么?她做错了什么 – 在use语句中使用预定义数组的正确方法是什么?
解决方法
模块Socket exports PF_INET和PF_INET6默认情况下,因此如果将其放入使用行中则无关紧要.但是Time :: HiRes does not export stuff默认情况下.
你严格得到的错误是:
Bareword “CLOCK_REALTIME” not allowed while “strict subs” in use …
这告诉我们Perl不知道CLOCK_REALTIME是一个sub,这是真的,因为当我们这样做时它没有被加载:
- my @consts = qw(CLOCK_REALTIME CLOCK_MONOTONIC);
- use Time::HiRes @consts;
- printf "%d,CLOCK_MONOTONIC;
What use
does需要模块并在编译时导入参数的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,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,1
所以回顾一下:
>这是因为两件事:范围和执行顺序
>传递数组的事实不是问题 – 数组将是传递的part of the LIST>如果你不使用严格,你不能轻易找到问题>如果你在使用前添加一个BEGIN块并将我的声明放在BEGIN之外,它就可以了>如果您采用require而不是使用并自行导入,您也可以传递数组