【问题标题】:export vs export_ok in perlperl 中的 export 与 export_ok
【发布时间】:2013-07-28 13:20:48
【问题描述】:

我无法理解 EXPORT_OKEXPORT 的区别/用例。
大多数资源都提到了以下内容:

@Export 允许将模块的函数和变量导出到 使用标准导入方法的用户命名空间。这样,我们不 需要为模块创建对象以访问其成员。
@EXPORT_OK 会根据选择列表的需要导出符号 模块的符号(子程序和变量)。

但我真的看不出这里的区别/意义。
有人可以提供一个小的基本示例来说明这两个符号的区别/用法吗?

【问题讨论】:

  • 如果有的话,你不应该默认导出很多符号。 @EXPORT 通常很小或为空。 @EXPORT_OK 可以包含更多内容。例如,Encode 默认导出encodedecode (@EXPORT),但不导出is_utf8 (@EXPORT_OK)

标签: perl perl-module


【解决方案1】:

假设我有一个使用 @EXPORT 的包 MyPackage

#this is MyPackage.pm
package MyPackage;
@EXPORT = qw(do_awesome_thing);

sub do_awesome_thing { ... }

sub be_awesome { ... }

现在,当我在代码中使用 MyPackage 时,

#this is myscript.pl
use MyPackage;

do_awesome_thing(); #works

be_awesome(); #doesn't work
MyPackage::be_awesome(); #works

do_awesome_thing 会自动从MyPackage 导出到我的代码,而无需我说“把这个给我”。 be_awesome 不会被导出(它也不会与@EXPORT_OK 一起导出,我只是展示这部分以让您清楚“导出”给我们带来了什么)。

另一方面,如果我有一个使用@EXPORT_OK 的包MyOtherPackage

#this is MyOtherPackage.pm
package MyOtherPackage;
@EXPORT_OK = qw(do_awesome_thing);

sub do_awesome_thing { ... }

sub be_awesome { ... }

然后尝试

#this is mynewscript.pl
use MyOtherPackage;

do_awesome_thing(); #doesn't work
MyOtherPackage::do_awesome_thing(); #works, as always

直接调用do_awesome_thing 的行不起作用。这是因为在@EXPORT_OK 中添加一些内容表示“仅在我的用户要求时才将其提供给我的用户”。由于我们刚刚说use MyOtherPackage 没有明确要求在此处导入do_awesome_thing,因此它不会被导入,并且只能通过指定包名来访问。

您要求导入do_awesome_thing 的方式是在上面mynewscript.pl 的第二行中说use MyOtherPackage qw(do_awesome_thing)。这表示导入该模块并使do_awesome_thing 直接可用。之后,上面mynewscript.pl 中的第四行将开始工作。

请注意,用户也可以在第一个包中指定use MyPackage qw(do_awesome_thing),在这种情况下,不会导出@EXPORT 列表中的任何其他内容,只会导出do_awesome_thing。因此,除了use PackageName; 的默认情况外,@EXPORT@EXPORT_OK 的行为相似。在默认情况下,@EXPORT 中的任何内容都会自动放入用户的脚本中,而@EXPORT_OK 则更有礼貌,不会导出任何内容。

【讨论】:

  • 使用@EXPORT,你只有两个选择...错了;只是错了。 @EXPORT@EXPORT_OK 的工作方式基本相同:在任何一种情况下,用户都可以指定他们希望导入的名称列表。它们在用户提供没有要导入的名称列表时发生的情况有所不同 - 在这种情况下,@EXPORT 上的内容被导出,@EXPORT_OK 上的内容被导出不是。
  • @tobyink 谢谢,没有与 EXPORT 合作太多所以不知道,我现在已经改变了那部分。在谷歌搜索以确认这一点时,我遇到了这本 O'Reilly 的书 (docstore.mik.ua/orelly/perl/advprog/ch06_05.htm),它似乎犯了同样的错误:“如果模块使用 EXPORT 而不是 EXPORT_OK ,用户将获得所有导出的符号,无论它们是否是否在进口清单中提及。”但我已经测试了这种行为并确认你是对的,而这本书(显然)是错的。
【解决方案2】:

来自fine Exporter manual

  • use YourModule;
    这会将 YourModule 的 @EXPORT 中的所有符号导入到 use 语句的命名空间中。
  • use YourModule ();
    这会导致 perl 加载您的模块,但不导入任何符号。
  • use YourModule qw(...);
    这仅将调用者列出的符号导入其命名空间。所有列出的符号都必须在您的@EXPORT@EXPORT_OK 中,否则会发生错误。像这样访问 Exporter 的高级导出功能,但列表条目在语法上与符号名称不同。

所以,如果你使用 @EXPORT 并且有人使用通常的 use YourModule;,那么你只是用 @EXPORT 中的所有内容污染了他们的命名空间。但是,如果您使用 @EXPORT_OK,他们必须明确要求导入一些东西,以便使用您的模块的人可以控制他们的命名空间发生的事情。

区别实际上在于谁控制进入user 命名空间的内容:如果您使用@EXPORT,那么模块是used,如果您使用@EXPORT_OK,那么执行导入的代码控制自己的命名空间。

当然,你总是可以说 use Whatever(); 来防止不礼貌的模块污染你的命名空间,但这很丑陋,你不应该纠结于想要在你的命名空间上乱涂乱画的粗鲁代码。

【讨论】:

  • 所以use YourModule qw(a b);@EXPORT qw(a b); 没有意义?如果不是,那么我仍然不明白为什么我们需要@EXPORT_OK
  • @Jim our @EXPORT 默认保存您导出的符号(即使用use YourModule;)。这样做被认为是一种不好的做法@EXPORT_OK 包含所有可以根据明确请求导出的符号列表。
猜你喜欢
  • 1970-01-01
  • 2016-02-10
  • 1970-01-01
  • 2018-12-31
  • 2017-03-10
  • 1970-01-01
  • 2020-07-26
相关资源
最近更新 更多