在 Perl 中,如何访问另一个包中定义的标量?

发布于 2024-10-06 11:04:33 字数 809 浏览 0 评论 0原文

我似乎被困在尝试访问另一个包中定义的标量,并将示例缩小为一个简单的测试用例,我可以在其中重现问题。 我希望能够使用我们的机制访问对包“Example”中定义的列表的引用,但是,Dumper 显示该变量在 example.pl 中始终未定义:

Example.pm如下所示:

#!/usr/bin/perl -w

use strict;
use warnings;
use diagnostics;

package Example;
use Data::Dumper;

my $exported_array = [ 'one', 'two', 'three' ];
print Dumper $exported_array;

1;

使用此包的代码如下所示:

#!/usr/bin/perl -w

use strict;
use warnings;
use diagnostics;
use Data::Dumper;

use lib '.';
use Example;

{ package Example;
  use Data::Dumper;
  our $exported_array;
  print Dumper $exported_array;
}

exit 0;

运行此代码后,第一个 Dumper 运行,一切看起来正常,之后,第二个 Dumper example.pl 运行,然后引用未定义:

$VAR1 = [
          'one',
          'two',
          'three'
        ];
$VAR1 = undef;

I seem to be stuck trying to access a scalar which is defined in another package, and have narrowed down an example to a simple test case where I can reproduce the issue.
What I wish to be able to do it access a reference to a list which is in defined within the package 'Example', using the our mechanism, however, Dumper is showing that the variable is always undefined within example.pl:

Example.pm looks like the following:

#!/usr/bin/perl -w

use strict;
use warnings;
use diagnostics;

package Example;
use Data::Dumper;

my $exported_array = [ 'one', 'two', 'three' ];
print Dumper $exported_array;

1;

And the code which uses this package looks like this:

#!/usr/bin/perl -w

use strict;
use warnings;
use diagnostics;
use Data::Dumper;

use lib '.';
use Example;

{ package Example;
  use Data::Dumper;
  our $exported_array;
  print Dumper $exported_array;
}

exit 0;

Upon running this code, the first Dumper runs and things look normal, after this, the second Dumper, example.pl runs and the reference is then undefined:

$VAR1 = [
          'one',
          'two',
          'three'
        ];
$VAR1 = undef;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

绮筵 2024-10-13 11:04:33

my 声明不会创建包级变量,也不会在任何命名空间的符号表中输入任何内容。

要执行您想要执行的操作,您必须将第一个文件中的声明更改为

our $exported_array = [ ... ];

您可以在另一个文件中访问它,如下所示

$Example::exported_array

A my declaration does not create a package level variable and does not enter anything onto the symbol table for any namespace.

To do what you look like you are trying to do, you will have to change the declaration in the first file to

our $exported_array = [ ... ];

You can then access it in another file as

$Example::exported_array
青衫负雪 2024-10-13 11:04:33

即使 $exported_array 未在 Example 包中按词法限定范围,Example$exported_arraymain 的 $exported_array 是两个不同的东西。更改您给出的示例的最简单方法是 1. 在 Example 声明中将 my 更改为 our 并显式限定变量名称。

our $exported_array;

...

print Dumper $Example::exported_array;

否则,您需要将 Example 设为 Exporter。 (或者只是编写一个 Example::import 例程 - 但我不会介绍这一点。)

package Example;
our $exported_array = ...;
our @EXPORT_OK = qw<$exported_array>;
use parent qw<Exporter>;

在脚本中:

use Example qw<$exported_array>;

但是,因为您实际上可以导出数组(不仅仅是参考文献),我会这样做:

our @exported_array = (...);
our @EXPORT_OK      = qw<@exported_array>;
...
use Example qw<@exported_array>;
...
print Dumper( \@exported_array );

Even if $exported_array weren't lexically scoped in the Example package, Example's $exported_array and main's $exported_array are two different things. The easiest way to change the example you've given is to 1. change my to our in the Example declaration and explicitly qualify the variable name.

our $exported_array;

...

print Dumper $Example::exported_array;

Otherwise, you need to make Example an Exporter. (Or just write an Example::import routine--but I' not going to cover that.)

package Example;
our $exported_array = ...;
our @EXPORT_OK = qw<$exported_array>;
use parent qw<Exporter>;

And in the script:

use Example qw<$exported_array>;

However, as you can actually export arrays (not just refs), I would make that:

our @exported_array = (...);
our @EXPORT_OK      = qw<@exported_array>;
...
use Example qw<@exported_array>;
...
print Dumper( \@exported_array );
2024-10-13 11:04:33

当您使用 my 运算符时,您将按词法将变量名称的作用域限定为您所在的作用域或文件。

如果您希望某些内容作为合格的包数组可见,则需要像在驱动程序代码中一样使用 our 。我相信您还需要在 .pm 文件中声明一些特殊的导出器变量,但从好的方面来说,您不需要在驱动程序文件中声明 our $exported_array;

When you use the my operator, you are lexically scoping the variable name to either the scope you're in or to the file.

If you want something to be visible as a qualified package array, you need to use our like you do in the driver code. I believe you also need to declare a few special exporter variables in the .pm file, but on the plus side you won't need to declare our $exported_array; in the driver file.

深居我梦 2024-10-13 11:04:33

对于较小的项目来说,使用 Exporter 没问题,但如果您有大量处理模块内部数据的代码,事情可能会变得……混乱。面向对象对于这种类型的事情要友好得多。

为什么不构造一个方法来获取这些数据呢?事实上,为什么不直接使用 Moose 呢?

在您的Example.pm中,只需加载Moose - 这会免费为您提供一个构造函数和析构函数,以及一个用于获取值的子例程默认情况下打开严格等。由于 Class:MOP(驼鹿角下的引擎)初始化属性的方式,数组引用的声明方式必须略有不同 - 您必须将其包装在代码引用(又名 sub {})中。您还可以在调用包的脚本中使用 Data::Dumper,而不是包本身。

example.pm

package Example;
use Moose;

has 'exported_array' => (is => 'rw', default => sub { [ 'one', 'two', 'three' ] });
1;

然后从脚本中调用它:

example.pl

#!/usr/bin/env perl
use Modern::Perl '2013';
use lib '.';
use Example;
use Data::Dumper;

my $example = Example->new;
my $imported_array_ref = $example->exported_array;
my @imported_array = @{$imported_array_ref};
foreach my $element(@imported_array) { say $element; }
say Dumper(\@imported_array);

我在上面的 example.pl 脚本中非常明确地取消引用...通过直接将其取消引用到数组中可以更加简洁:

#!/usr/bin/env perl
use Modern::Perl '2013';
use lib '.';
use Example;
use Data::Dumper;

my $example = Example->new;
my @imported_array = @{$example->exported_array};
foreach my $element(@imported_array) { say $element; }
say Dumper(\@imported_array);

我认为很多 如果有更多简单的例子来展示如何完成简单的事情,更多的 Perl 程序员会接受 Moose。

官方驼鹿手册非常好,但它是确实是为那些已经熟悉 OOP 的人编写的。

Using Exporter is fine for smaller projects, but if you have lots of code handling data that is internal to a module, things can get ... messy. Object-orientation is a lot friendlier for this type of thing.

Why not construct a method to fetch this data? In fact, why not just use Moose?

In your Example.pm, just load Moose - this gives you a constructor and destructor for free, as well as a subroutine to fetch values and turns on strict, etc by default. Array references have to be declared a little differently, due to how Class:MOP (The engine under the antlers of Moose) initializes attributes - you have to wrap it in a code reference (aka sub {}). You would also use Data::Dumper in the script which calls the package, instead of the package itself.

Example.pm

package Example;
use Moose;

has 'exported_array' => (is => 'rw', default => sub { [ 'one', 'two', 'three' ] });
1;

Then call this from a script:

example.pl

#!/usr/bin/env perl
use Modern::Perl '2013';
use lib '.';
use Example;
use Data::Dumper;

my $example = Example->new;
my $imported_array_ref = $example->exported_array;
my @imported_array = @{$imported_array_ref};
foreach my $element(@imported_array) { say $element; }
say Dumper(\@imported_array);

I made the dereferencing really explicit in the example.pl script above... it can be much more terse by dereferencing it directly into the array:

#!/usr/bin/env perl
use Modern::Perl '2013';
use lib '.';
use Example;
use Data::Dumper;

my $example = Example->new;
my @imported_array = @{$example->exported_array};
foreach my $element(@imported_array) { say $element; }
say Dumper(\@imported_array);

I think a lot more Perl programmers would embrace Moose if there were more simple examples that show how to get simple things done.

The Official Moose Manual is excellent, but it was really written for those who are already familiar with OOP.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文