在Perl中,如何从库中导入哈希?

Ros*_*ers 2 perl hash scope perl-module

我有一个文件revs.pm:

my %vers = ( foo => "bar" );
Run Code Online (Sandbox Code Playgroud)

另一个文件如importer.pl:

use revs;
Run Code Online (Sandbox Code Playgroud)

如何访问%versimporter.pl

Mik*_*l S 13

创建一个适当的模块,并改变我的关键字来我们:

# revs.pm
package revs;

our %vers = ( foo => "bar" );

1; # Perl modules need to return a boolean "true" value.

# importer.pl
use revs;

print $revs::vers{foo} . "\n";
Run Code Online (Sandbox Code Playgroud)

  • 当然,你的意思是说'我们的%vers'而不是'my%vers`.:-P (3认同)
  • 请记住,全局变量是邪恶的,因此使用访问器方法可能会更好.:) (3认同)

too*_*lic 9

另一种传统方法是在包中使用Exporter模块,并导出变量:

package revs;
use strict;
use warnings;
require Exporter;
our @ISA    = qw(Exporter);
our @EXPORT = qw(%vers);
our %vers   = (foo=>'bar');
1;
Run Code Online (Sandbox Code Playgroud)

这避免了在引用变量时必须使用包名importer.pl:

use strict;
use warnings;
use Data::Dumper;
use revs;
print Dumper(\%vers);
Run Code Online (Sandbox Code Playgroud)

一个缺点是您必须确保您的变量名称是唯一的,以避免名称冲突.


jro*_*way 6

或者,您可能不会将程序的某些部分与全局变量耦合在一起.考虑在一个模块中使用此哈希时会发生什么:

package Foo;
use MyApp::Versions qw(%versions); # i'm going to pretend that you didn't call the module "revs".

some_function {
    while(my ($k, $v) = each %versions){
       return if $some_condition;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在其他一些模块中:

package Bar;
use MyApp::Versions qw(%versions);

some_other_function {
    while(my ($k, $v) = each %versions){
       print "$k => $v\n";
    }
}
Run Code Online (Sandbox Code Playgroud)

然后使用两个模块:

use Foo;
use Bar;

some_other_function;
some_function;
some_other_function;
Run Code Online (Sandbox Code Playgroud)

根据$some_condition,some_other_function每次调用时都会产生不同的结果.有趣的调试.(这each比全局状态问题更具问题;但是通过公开内部实现,您允许调用者执行您不想要的操作,这很容易破坏您的程序.)

例如,当您将硬编码哈希值更改为按需数据库查找时,重写Foo和Bar也很痛苦.

所以真正的解决方案是设计一个合适的API,并导出而不是整个变量:

package MyApp::Versions;
use strict;
use Carp qw(confess);
use Sub::Exporter -setup => {
    exports => ['get_component_version'],
};

my %component_versions = ( foo => 42 ); # yes, "my", not "our".

sub get_component_version {
    my ($component) = @_;
    return $component_versions{$component} ||
        confess "No component $component!"
}

1;
Run Code Online (Sandbox Code Playgroud)

现在您的模块更易于使用:

package Foo;
use MyApp::Versions qw(get_component_version);

sub some_function {
    die 'your foo is too old'
        unless get_component_version('foo') >= 69;

    return FooComponent->oh_hai;
}
Run Code Online (Sandbox Code Playgroud)

现在some_function无法搞砸some_other_function,当你改变get_component_version的实现时,你的程序的其余部分将无关紧要.