【问题标题】:How to import all "our"-variables from the unnamed Perl module without listing them?如何从未命名的 Perl 模块导入所有“我们的”变量而不列出它们?
【发布时间】:2011-09-12 17:00:34
【问题描述】:

我需要从 未命名 Perl 模块 (Module.pm) 导入所有 我们的 变量,并在 Perl 脚本 (Script.pl) 中使用它们。

以下代码在没有 "use strict" 的情况下运行良好,但使用它失败了。如何更改此代码以使用 "use strict" 而无需手动列出所有导入的变量(如other question 的答案中所述)?

非常感谢您的帮助!

脚本.pl:

use strict;
require Module;
print $Var1;

模块.pm:

our $Var1 = "1\n";
...
our $VarN = "N\n";
return 1;

运行脚本:

$> perl Script.pl

错误:

Global symbol "$Var1" requires explicit package name at Script.pl line 3.
Execution of Script.pl aborted due to compilation errors.

注意 (1):模块未命名,因此不能使用 Module:: 前缀。

注意 (2)Module.pm 还包含一组由全局变量配置的函数。

注意(3):变量不同,不应存储在一个数组中。

注意(4):设计不好,但问题不在于设计。它是关于强制列出的代码以复杂性O(1) 的最小修改工作,即不依赖N 的几行代码。

候选解决方案(已接受):在所有导入的变量之前添加 $::。它与strict 兼容,还允许在代码中将my 变量与imported 区别开来。

【问题讨论】:

  • 如果你需要颠覆use strict那么你最好不要使用strict。
  • @evil otto - 我需要 strict 来发现程序中的其他问题。
  • 如果您要导出 1000 个变量,那么您做错了。
  • @ikegami - 这个数字确实是 50 左右。
  • 50 也是如此。事实上,导出 any 变量通常不是最理想的。

标签: perl import module global-variables


【解决方案1】:

将您的脚本更改为:

use strict;
require Module;
print $Module::Var1;

问题是$Var1 不在主命名空间中,它在Module 的命名空间中。

编辑: 正如下面的 cmets 所指出的,您尚未命名您的模块(即顶部没有显示 package Module;)。因此,没有Module 命名空间。将脚本更改为:

use strict;
require Module;
print $main::Var1;

...允许脚本正确打印出1\n

【讨论】:

  • 由于$Var1 位于“未命名”模块中,正如 OP 所称,它位于 main 命名空间中。使用$main::Var1 甚至只是$::Var1 访问以符合strict
  • @aponomarenko:我已经编辑了答案以反映暴民的评论。编辑后的脚本现在可以与您的“未命名”模块一起使用。
  • 有没有办法不为每个变量添加 $main::** 或 **$:: ?类似于从 $main::VarN$VarN 的别名?
  • @aponomarenko:除非您可以将Module.pm 编辑为适当的模块,然后导出您要导出的所有变量。
  • @CanSpice - 我想全部导出。是否可以使用一些“内部”Perl 函数将它们全部导入,但不能手动列出它们?类似于返回模块中声明的全局变量列表的函数 A 和按名称导入变量的函数 B 之类的东西,所以我可以写:foreach my $Var (A(Module)) {B($Var);}?
【解决方案2】:

如果您必须在每个模块中导入所有 我们的 变量,则说明您的设计存在严重问题。我建议您重新设计程序以分离元素,以便它们之间的串扰最少。这称为decoupling

【讨论】:

  • 是的,但不幸的是,重新设计代码为时已晚。我需要将内部模块从一个非常大的脚本(20.000 行)中分离出来,并尽量减少回归,因为它的生产时间大约为 2 年。
  • 不过,设计还不错。它只是由多个全局变量而不是参数配置的一些函数。
【解决方案3】:

您想从一个模块中导出所有变量,并且您想以一种您甚至不知道要导出什么的方式来执行此操作?忘记use strictuse warnings,因为如果你把它们放在你的程序中,它们只会尖叫着跑出去,然后蜷缩在角落里歇斯底里地哭泣。

我从不,我不是说几乎从不,从不导出变量。我总是创建一种方法来提取所需的值。它使我能够对我向外界公开的内容进行重要控制,并保持用户的命名空间纯净。

让我们看看你的想法可能存在的问题。

  1. 您不知道在您的模块中导出了什么。使用该模块的程序如何知道要使用什么?在某个地方,您必须记录变量 $foo@bar 可供使用。如果必须这样做,何不干脆稳妥行事?
  2. 您遇到有人更改模块的问题,突然一个新变量正在使用该模块导出到程序中。想象一下,如果该变量已经在使用中。程序突然出现了一个错误,你永远也想不通。
  3. 您正在导出模块中的变量,而开发人员决定修改该变量,甚至将其从程序中删除。同样,由于您不知道正在导入或导出什么,因此无法知道程序中突然出现错误的原因。

正如我所提到的,您必须知道程序可以使用的模块中正在使用的东西,因此无论如何您都必须记录它。如果您要坚持导入变量,至少使用EXPORT_OK 数组和导出器模块。这将有助于限制损害。这样,您的程序可以声明它所依赖的变量,并且您的模块可以声明它知道程序可能正在使用的变量。如果我正在修改模块,我会格外小心看到我正在导出的任何变量。而且,如果您必须在程序中指定要导入的变量,您就知道要谨慎对待这些特定变量。

否则,为什么还要麻烦模块呢?为什么不直接回到 Perl 3.0 并使用 require 而不是 use 并忘记使用 package 语句。

【讨论】:

  • 设计不好,但问题不在于设计。而且我正在使用require 没有package 问题中所述的声明。不过,谢谢。
【解决方案4】:

听起来您的文件中有数据,并试图将这些数据加载到您的程序中。

现在,模块中的our 声明仅声明该文件范围的变量。一旦文件完成运行,要访问变量,您需要使用它们的完全限定名。如果您的模块有package xyz; 行,则完全限定名称为$xzy::Var1。如果没有package 声明,则使用默认包main,将变量命名为$main::Var1

但是,任何时候如果您要使用数字名称更改许多变量,您可能应该使用数组。

将您的模块更改为:

@My::Module::Data = ("1\n", "2\n" ... )

然后按索引访问项目:

$My::Module::Data[1]

【讨论】:

  • 模块包含数据和使用这些数据的函数。变量具有不同的名称,因此不能通过索引访问(当然,它们可以重写为具有不同字符串索引的一个哈希,但这不是我的选择)。是否可以一次将所有 $main::VarN 别名为 VarN?
  • main 是内置命名空间。为什么我需要明确选择它?有没有办法为脚本选择默认命名空间并避免在每个变量之前写 $main:: ?
  • main:: 是内置命名空间,默认情况下可供您使用。唯一迫使您编写它的是strict pragma,它需要从另一个包中导入变量,使用myour 声明或完全限定。您可以将main:: 缩写为::,使您的变量名称为$::Var1。有一些“方法”可以在模块中搜索变量并编写代码将它们“导入”到调用模块中,但它们都不是特别健壮的,这就是为什么我不愿发布一个。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-07-21
  • 2013-12-11
  • 1970-01-01
  • 2010-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多