In Perl, how can I access a scalar defined in another package?

a 夏天 提交于 2020-01-23 06:53:26

问题


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;

回答1:


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 );



回答2:


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



回答3:


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.




回答4:


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.



来源:https://stackoverflow.com/questions/4379257/in-perl-how-can-i-access-a-scalar-defined-in-another-package

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!