【问题标题】:Can't use Exporter properly无法正确使用 Exporter
【发布时间】:2018-06-13 16:16:36
【问题描述】:

我已经在包含Exporter 语句的更大代码块上浪费了很多天,这在大约一年前曾经可以工作。这方面的几个变体都失败了,包括安装 ./FOO/BAR/Foobar.pm 表示成功。

我使用的是 Windows 10,Perl v5.26.0,专为 MSWin32-x64-multi-thread 构建

来电者.pl

   #!/usr/bin/perl

   use lib ".";
   use lib "./FOO/BAR";

   use strict;
   use warnings;

   use FOO::BAR::Foobar;

   print "try FOO::BAR::Foobar::foo()\n";
   FOO::BAR::Foobar::foo();  # perl can't find this

   print "try foo()\n";
   foo();          # errors out - can't find &main::foo

   print "done\n";

./FOO/BAR/Foobar.pl

#!/usr/bin/perl -w

use strict;
use warnings;

package Foobar;

our($VERSION , @ISA , @EXPORT , @EXPORT_OK , %EXPORT_TAGS , $FOO);

BEGIN {
    require Exporter;
    @ISA       = qw(Exporter);
    @EXPORT_OK = qw(foo);
}

sub foo {
    print "Loaded\n";
    $FOO = q{some val};
}

1;

执行转储

perl Caller.pl
try FOO::BAR::Foobar::foo()
Undefined subroutine &FOO::BAR::Foobar::foo called at Caller.pl line 12.

发生了什么事?我应该放弃使用Exporter 吗?那么如何跨模块链接功能呢?

【问题讨论】:

  • 尝试将文件顶部的package Foobar 替换为package FOO::BAR::Foobar ./FOO/BAR/Foobar.pl
  • 值得指出的是,模块文件通常从不运行,所以 shebang 行 #!/usr/bin/perl -w 只是一个注释,应该删除。
  • “我在一大段代码上浪费了很多天,其中包含 Exporter 语句,这在大约一年前就可以工作了”关于 Perl 中的错误的东西,这比您的错误可能性要小得多。如果您没有更改“更大的代码块”,它仍然会运行,这是您应该在“很多天”前尝试的第一件事。
  • 提示:. 是 CWD,不需要脚本目录。由于您想要脚本的目录,请改用$RealBin(在执行use FindBin qw( $RealBin ); 之后)。例如use FindBin qw( $RealBin ); use lib $RealBin, "$RealBin/FOO/BAR";

标签: perl exporter


【解决方案1】:

出了三件事:

  1. FOO::BAR::Foobar::foo():没有sub,只有Foobar::foo()

  2. 使用foo()use FOO::BAR::Foobar; 等效于BEGIN { require FOO::BAR::Foobar; FOO::BAR::Foobar->import() },但在包FOO::BAR::Foobar 中没有可用的方法import,因为您将Exporter 继承到包@ 中987654331@.

  3. 使用foo():您使用的是@EXPORT_OK 而不是@EXPORT,这意味着您需要显式导入foo,但您没有在use FOO::BAR::Foobar; 中这样做。

所以需要做两件事来解决这个问题:

  1. 正如@HåkonHægland 在评论中已经指出的,将package Foobar; 更改为package FOO::BAR::Foobar;

  2. use FOO::BAR::Foobar; 更改为use FOO::BAR::Foobar qw/foo/;

那么您显示的代码将起作用 - 无需放弃 Exporter。我只是推荐使用Exporter 的不同风格:不要通过@ISA 继承,只需将import 导入您的包中。这是我将如何编写您的文件./FOO/BAR/Foobar.pm

package FOO::BAR::Foobar;
use strict;
use warnings;

use Exporter 'import';
our @EXPORT_OK = qw(foo);

our $FOO;
sub foo {
    print "Loaded\n";
    $FOO = q{some val};
}

1;

【讨论】:

  • 1.和2.基本上都是“你的包和文件有错误的名字”require Exporter 很好,只要 @ISA = qw(Exporter) 也在那里。我还注意到 OP 说该软件包位于 ./FOO/BAR/Foobar.pl(而不是 .pm)中,这根本不起作用。
  • @Borodin 是的,它们是,因此两者只有一个解决方案 - 这是我对 OP 问题 “发生了什么?” 的回答。我认为Foobar.pl 只是一个错字,因为稍后在帖子中命名了正确的文件,否则 OP 会看到不同的错误消息,但你指出它是对的。
  • @Borodin 至于@ISA=("Exporter");,是的,这是一个可以接受的方法——只是这个包也会继承Exporter的所有其他方法,尽管大多数模块只需要import,因此我对use Exporter 'import';的建议。
  • 好的。我对您的第 2 点感到困惑。您似乎在暗示 require Exporter 不正确。我确实同意use Exporter 'import' 更可取,但不是因为你说的原因:一个模块应该是要么 一个库(当Exporter 可以使用任何一种方式时)或一个OO 模块(当Exporter 无关紧要)而不是两者兼而有之。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-01
  • 2020-03-22
  • 1970-01-01
  • 2021-09-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多