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

问题描述 投票:2回答:4

我花了两个小时来追踪这个错误。我可以解决它,但我不明白。

如果我有一个看起来像这样的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,然后在子类中实现该方法。所以我不希望在importing父类时自动调用这个use方法。

我查看了perlootutperlobj并没有看到任何提及此事。

perl packages
4个回答
7
投票

import()是Perl中的特殊方法名称。每当你use一个模块时,Perl会在该模块中寻找一个名为import()的子程序,如果找到它,它将被运行。

这通常用于Exporter聪明。这意味着你的模块中有一个名为import()的方法,你不想在加载模块时调用它是一个非常糟糕的主意。它会让你在任何时候都与Perl作战。

有关更多信息,请参阅perldoc -f import

导入列表

没有内置的import功能。它只是希望将名称导出到另一个模块的模块定义(或继承)的普通方法(子例程)。 use函数调用所用包的import方法。另见useperlmodExporter

你找到的“解决方法”也不是一个好主意。您正在从名为Foo.pm的文件中有效地加载一个名为My:Foo的模块,如果文件名和包名称不匹配,Perl将会非常困惑。


6
投票

在我看来,你正在寻找这头骆驼的错误结局。你的问题不是由import“特殊”引起的,而是由于不知道use究竟是做什么的。根据perldoc useuse Module与“完全相同”

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

当你使用use时,你告诉Perl调用Module的import方法。就那么简单。

当然,Perl是Perl,你的import方法可能有一些方法可以确定它是否被称为use的一部分,并且如果是这样的话会立即返回,但这只会增加不必要的复杂性。将方法重命名为更具描述性的方法(例如,import_fileimport_record等,取决于您实际导入的内容)将是一个更好的解决方案。


3
投票

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调用,如果给出了一个明确的空列表,则省略导入调用(如后面的文档所述)。

(还要注意Module-> import(如果它存在则调用Module()函数然后在返回的任何内容上调用import方法)和Module :: - > import或'Module' - > import这是一个细微的区别。在Module类上直接调用类方法。)


3
投票

import是保留的关键字。当你use一个模块时,将调用它的import方法,参见the documentation

我担心你无法改变这一点。将您的方法重命名为其他不是特殊关键字的方法。

© www.soinside.com 2019 - 2024. All rights reserved.