如何在 perl 的本地范围内访问导入模块中的变量?

how to access variables in imported module in local scope in perl?

我在创建 perl Moose 模块时卡住了。

我有一个全局 pm 模块。

package XYZ;
require Exporter;
our @ISA = qw(Exporter);  ## EDIT missed this line 
our @EXPORT_OK = qw($VAR);
my $VAR1 = 1;
our $VAR = {'XYZ' => $VAR1};
1;

我想在我正在创建的 Moose 模块中获得 $VAR

package THIS;
use Moose;
use YAML::XS;
sub get_all_blocks{
  my ($self) = @_;
  require $self->get_pkg(); # this returns the full path+name of the above package
  # i cannot use use lib+use since the get_pkg starts complaining 

  our $VAR;
  print YAML::XS::Dump($XYZ::VAR); # this works
  print YAML::XS::Dump($VAR); # this does not work
  # i cannot use the scope resolution since XYZ would keep changing.

}
1;

有人可以帮我访问变量吗?

编辑:package XYZ 代码中遗漏了一行。 我无法触摸 package XYZ,因为它是其他人 owned/used,我可以使用它:(

您不希望 our $VAR;THIS 的命名空间中。这创建了对 $THIS::VAR 的词法引用。不是你想要的。

相反,您需要 use 正确:

use XYZ qw($VAR);

但是,XYZ 在这里没有 import 到 运行,因此您需要更新它。有两种方法可以修复 XYZ 来执行此操作 - 一种是导入导入,例如 use Exporter qw(import);,另一种是导出 Exporter,例如 use parent qw(Exporter);。这两个都会使 XYZ->import(...) 正常工作。

一旦 XYZ useing Exporter 正确,那么 use XYZ qw($VAR); 行将导致 perl 隐式加载 XYZ 并调用 XYZ->import(qw($VAR)),这将将该变量导入您的命名空间。

现在,在回答了您的问题后,我将与其他人一起建议导出变量是一种非常糟糕的代码味道,并且可能不是执行您想要的操作的最佳/最干净的方法。

导出变量容易出问题

为什么不

package XYZ;

use strict;
use warnings;

use Exporter qw(import);
our @EXPORT_OK = qw(get_var);

my $VAR = '...';  # no need for "our" now

sub get_var { return $VAR }
...
1;

然后

package THIS;

use warnings;
use strict;

use XYZ qw(get_var);

my $var = get_var();    
...
1;

参见 Exporter

至于你想做什么,有两个直接的问题

    来自 XYZ
  • $VAR 永远不会导入到 THIS。如果你需要来自其他包的符号,你需要导入它们。 这些包必须首先使它们可用,所以你也需要将它添加到 @EXPORT_OK。 与上面一样,但使用 $VAR 而不是 get_var()

    package XYZ;
    ...
    use Exporter qw(import);
    our @EXPORT_OK = qw($VAR);
    
    our $VAR = '...';  # need be "our" for this
    

    package THIS;
    ...
    use XYZ qw($VAR);
    
    print "$VAR\n";
    

    现在$VAR可以直接使用,包括被写入(除非声明常量);它可以在其他代码的脚下改变它的值,而这些代码可能永远不知道其中的任何一个。

    另一种方法是使用 @EXPORT,然后将这些符号引入到每个显示 use Package; 的程序中。我强烈建议仅在调用者需要明确列出他们想要的内容时才使用 @EXPORT_OK。这也很好地记录了正在使用的内容。

  • 即使添加了它,THIS 中仍然有一个同名变量,它隐藏(遮罩、阴影)$XYZ::VAR。所以删除 THIS 中的 our $VAR。这是全局问题的一个很好的例子。一旦引入它们,我们就必须小心 alwayseverywhere.

但是跨模块共享变量存在更大的问题。

它使代码组件纠缠在一起,代码变得越来越难处理。它违背了明确定义的范围和模块化设计的原则,它支持远距离操作等。Perl 提供了许多用于构建代码的好工具,我们很少需要全局变量和共享变量。它告诉 Exporter 本身 warns against that.

请注意现在 XYZ 中的 my $VARXYZ 之外不可见; XYZ 之外的任何代码都无法知道或访问它。 当它是 our 时,解释器中的任何代码都可以编写它就像 $XYZ::VAR,甚至没有导入它;这就是我们想要的。

当然可能需要或很好地使用导出变量,偶尔可以在模块中找到。不过这是一个例外,要谨慎谨慎地使用。


除非通过 our in their package 在词法别名下将它们声明为包全局变量,在这种情况下它们可以在 任何地方使用 作为 $TheirPackageName::varname.

完成 privacy is courtesy of my.