directory/.pm 曾经是一个约定吗?它为啥存在?
Posted
技术标签:
【中文标题】directory/.pm 曾经是一个约定吗?它为啥存在?【英文标题】:Was directory/.pm ever a convention, and why does it exist?directory/.pm 曾经是一个约定吗?它为什么存在? 【发布时间】:2020-03-25 05:17:13 【问题描述】:Having just figured out this,我想知道-M
将如何处理附加到包名称的终端::
,
$ perl -MFoo:: -e1
我得到的是……
在
@INC
中找不到Foo/.pm
(您可能需要安装Foo::
模块)(@INC
包含:[...])。
这似乎表明它不起作用,所以好奇心迫使我......
$ mkdir Foo;
$ echo "package Foo sub k die 42 ; 1;" > Foo/.pm
$ PERL5LIB=. perl -MFoo:: -e'Foo::->k'
这确实有效。是否支持 use mod::;
解析为 mod/.pm
的约定?这是从古代遗留下来的。这种行为是从哪里来的?
有了这个架构我可以做到,
Foo/.pm # package Foo
Foo/Bar/.pm # package Foo::Bar
Foo/Bar/Baz/.pm # package Foo::Bar::Baz;
那我就可以了
use Foo::; # resolves to Foo/.pm
use Foo::Bar::; # resolves to Foo/Bar/.pm
use Foo::Bar::Baz::; # resolves to Foo/Bar/Baz/.pm
Foo::->new;
Foo::Bar::->new;
Foo::Bar::Baz::->new;
我喜欢这个,因为这增加了
的好处-
让我的所有课程都变成空话。
在
use
和调用之间添加一致性。
这个设计是有意的吗?它在任何地方都有记录吗?以前有没有人想过这个很棒的主意?
【问题讨论】:
我想念这比不使用尾随 :: 使您的课程裸词和use
和调用之间的一致性更好。而且我希望如果 P5P 觉得这令人困惑并去除了尾部斜线,他们会毫不犹豫地删除它,尽管我怀疑是否会有任何动力对此采取任何行动。
我在顶部有一个链接。本质上,如果您有一个名为Foo::Bar
的包并且您使用Foo::Bar->new
调用,那么如果您有一个package Foo sub Bar "Baz"
,您实际上是在执行( Foo::Bar() )->new
,即"Baz"->new
。所以你可以做Foo::Bar::->new
来解决这个问题,但是你的use
导入是不同的。有趣的是,您也可以安装 use Foo::Bar::
来工作。那么你的use
和你对包的引用是一样的。 use Foo::Bar::; Foo::Bar::->new
【参考方案1】:
这是使用 mod::; 的约定吗?解析到 mod/.pm 支持?
没有。
解析器在接受::
时过于宽松,让你做一些相当荒谬的事情。
$ cat Foo/Bar.pm
package Foo::Bar;
sub import print "imported.\n";
print "loaded.\n";
1
$ perl -I. -e'require Foo::Bar'
loaded.
$ perl -I. -e'require Foo::::::Bar'
loaded.
使用非规范形式会导致问题。
$ perl -I. -e'use Foo::Bar; use Foo::Bar; use Foo::Bar;'
loaded.
imported.
imported.
imported.
$ perl -I. -e'use Foo::::::Bar; use Foo::::::Bar; use Foo::Bar;'
loaded.
loaded.
imported.
同样,use Foo::Bar::
加载 Foo/Bar/.pm
不应被视为有意支持的功能。
以前有没有人想过这个很棒的主意?
实际上会一团糟。
对于初学者,您必须使用use Foo::Bar::;
而不是use Foo::Bar;
。
$ cat Foo/Bar/.pm
package Foo::Bar;
sub import print "imported.\n";
sub baz print "ok.\n";
1
$ perl -I. -e'use Foo::Bar;'
Can't locate Foo/Bar.pm in @INC ...
$ perl -I. -e'use Foo::Bar::;'
$
但是使用use Foo::Bar::;
是不够的,因为从未调用过import
。 package 指令需要与要调用的 import
的文件名 (package Foo::Bar::
) 匹配,这意味着您还必须调整对包的限定引用。
$ cat Foo/Bar/.pm
package Foo::Bar::;
sub import print "imported.\n";
sub baz print "ok.\n";
1
$ perl -I. -e'use strict; use Foo::Bar; Foo::Bar::baz();'
Can't locate Foo/Bar.pm in @INC ...
BEGIN failed--compilation aborted at -e line 1.
$ perl -I. -e'use strict; use Foo::Bar::; Foo::Bar::baz();'
imported.
Undefined subroutine &Foo::Bar::baz called at -e line 1.
$ perl -I. -e'use strict; use Foo::Bar::; Foo::Bar::::baz();'
imported.
ok.
说白了,这是不可取的。
即使您的模块此时没有 import
方法,也可能会发生变化,并且加载模块时使用两种不同且不兼容的约定是有害的。
这种行为从何而来
虽然表达式 Foo::Bar::
生成字符串 Foo::Bar
,但 use
不采用表达式。
此外,文字被传递给包名到文件名音译的实现,不执行完整性检查。 Perl 简单地执行一个相当于调用以下 sub 的操作:
sub pkg_to_qfn ( $_[0] =~ s::/gr ) . '.pm'
【讨论】:
【参考方案2】:这个约定的一个小缺点是它打破了之前的假设,即Foo/Bar.pm
在Foo/Bar.pm
中。所以没有终端 ::
的 use
语句不起作用,
mkdir Foo
mkdir Foo/Bar
echo "package Foo::Bar sub baz 1" > Foo/Bar/.pm
# Dies can't resolve to file,
PERL5LIB=. perl -MFoo::Bar -e1
Can't locate Foo/Bar.pm in @INC ...
# Works fine.
PERL5LIB=. perl -MFoo::Bar:: -e1
所以Foo::Bar::->new
语法与已经工作的use
代码兼容。虽然更改模块的位置会破坏与旧的 use
语句的兼容性,(因此它们也必须更新)。
【讨论】:
使用Foo/Bar/.pm
不仅会“破坏”与use Foo::Bar;
的兼容性,还会阻止调用模块的导入方法。以上是关于directory/.pm 曾经是一个约定吗?它为啥存在?的主要内容,如果未能解决你的问题,请参考以下文章
这个算法有名字吗? (我一直称它为changeBinary)
Swift:XCTest 会修改状态吗?可以返回可选值的测试函数的约定是啥?
使用 mvvmcross,我如何“共享”一个视图模型以使用 iphone 的视图和 ipad 的另一个视图?有啥特殊的命名约定吗?