perl import子例程有什么特别之处?

tag5nh1u  于 2022-11-15  发布在  Perl
关注(0)|答案(4)|浏览(157)

我花了两个小时找出这个错误。我可以解决它,但我不明白它。
如果我有一个perl模块./lib/My/Foo.pm,看起来像这样:

package My::Foo;

sub import {print "importing\n"}

1;

然后使用它隐式调用import子例程:

$ PERL5LIB=./lib perl -MMy::Foo -e 'print "ok\n"'
importing
ok

但是如果我复制同一个模块,并且使用它时不带冒号,那么import子例程不会被调用。

$ cp lib/My/Foo.pm lib/Foo.pm
$ PERL5LIB=./lib perl -MFoo -e 'print "ok\n"'
ok

如果我把import改成do_import,子例程就不会被调用。所以我可以避免这种行为。但是在我的真实的用例中,我有一个Import类和一个抽象方法import,然后在子类中实现这个方法。所以我 * 不 * 希望在use调用父类时自动调用这个import方法。
我查看了perlootutperlobj,没有看到任何提到这一点。

rxztt3cl

rxztt3cl1#

import()是Perl中的一个特殊方法名。每当您对一个模块执行use操作时,Perl都会在该模块中查找一个名为import()的子例程,如果找到了,它就会运行。
这是Exporter最常用的技巧。这意味着在模块中有一个名为import()的方法,而您不希望在加载模块时被调用,这是一个非常糟糕的主意。它会让您在每个回合都与Perl战斗。
请参阅perldoc -f import以取得更多信息:

导入列表

没有内置的import函数。它只是一个普通的方法(子例程),由希望将名称导出 * 到另一个模块的模块定义(或继承)。use函数调用所用包的import方法 *。另请参阅use、perlmodExporter
您找到的“变通方法”也不是一个很好的主意。您实际上是从一个名为www.example.com的文件中加载一个名为My:Foo的模块Foo.pm如果文件名和包名不匹配,Perl会感到非常困惑。

qni6mghb

qni6mghb2#

在我看来,您似乎看错了 Camel 的一头。您的问题不是由于import“特殊”而引起的,而是由于不知道use实际上是做什么的。根据perldoc useuse Module“完全等价于”

BEGIN { require Module; Module->import( LIST ); }

当您使用use时,* 您是在告诉Perl调用Module的import方法。* 就这么简单。
当然,Perl就是Perl,import方法可能有某种方法来判断它是否作为use的一部分被调用,如果是这样的话,就立即返回,但这只会增加不必要的复杂性。(例如,import_fileimport_record等,取决于您实际导入的内容)将是一个更好的解决方案。

camsedfj

camsedfj3#

import在两个方面是特殊的:
除非use被显式地给定了一个空的导入列表(例如use Foo ();),否则import将在编译时作为类方法被调用,并传递任何给定的导入列表参数use
如果import作为示例或类方法调用(无论是由use隐式调用还是显式调用),并且不存在这样的方法,则将返回一个空列表,而不是引发Can't locate object method错误或调用AUTOLOAD。
如果它在今天实现,它可能会被称为IMPORT
以上所有内容也适用于unimport(但使用no而不是use)。
更新:有些人链接到文档,其中说什么use是“完全等同的”,然后谎言。
它完全等同于BEGIN { require Module; Module::->VERSION(...); Module::->import(...) },只是如果没有指定版本,则省略VERSION调用;如果给出了明确的空列表,则省略import调用(如后面的文档所述)。
(Also注意Module-〉import(如果存在,则调用Module()函数,然后对返回的任何内容调用import方法)与Module::-〉import或'Module'-〉import(对Module类的直接类方法调用)之间的细微区别。

8ljdwjyq

8ljdwjyq4#

import是一个保留的关键字。当你use一个模块时,它的import方法将被调用,参见the documentation
恐怕你不能改变它。把你的方法重命名为其他的不是特殊关键字的东西。

相关问题