Perl:使用模块@list

标签 perl perl-module

有人想在 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。分别编辑。

她的结论是use Module @list没有按她的预期工作。

对此最好的解释是什么?她做错了什么 - 在 use 中使用预定义数组的正确方法是什么?陈述?

最佳答案

这与执行代码的时间有关。 use在编译时执行,而 my @list仅在运行时执行。所以数组在模块加载点不存在。

模块Socket exports PF_INETPF_INET6默认情况下,所以不管你把它放在 use线。但是时间::HiRes does not export stuff默认情况下。

你得到的错误 strict是:

Bareword "CLOCK_REALTIME" not allowed while "strict subs" in use ...



这告诉我们 Perl 不知道 CLOCK_REALTIME是一个子,这是真的,因为当我们这样做时它没有被加载:
my @consts = qw(CLOCK_REALTIME CLOCK_MONOTONIC);
use Time::HiRes @consts;
printf "%d, %d\n", CLOCK_REALTIME, CLOCK_MONOTONIC;

What use doesrequire模块和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 中可用 block 的范围,并且该值已经设置,因为 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而不是 useimport你自己,你也可以传递一个数组
  • 关于Perl:使用模块@list,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20396722/

    相关文章:

    Perl fork exec,父系统中的系统并杀死子系统

    Perl:如何以递归方式停止 File::Find 进入目录?

    perl - 当迭代进入 foreach 循环时打印不起作用

    php - 启用 OCS Inventory WebService 接口(interface)以查询 Assets 数据

    xml - 如何使用 Twig 模块从 XML 中删除注释

    perl - 引用带有标量的子例程

    perl - 使用循环抛出的 Test::Warn 测试错误

    perl - 设置Perl模块参数并同时使用Exporter

    perl - 如何使用 perl 搜索压缩文件中的文本

    perl - 如何在 DBD::Pg 中使用 pg_putcopydata 插入空值?