27

许多年前,我记得一位程序员同事这样建议:

new Some::Class;    # bad! (but why?)

Some::Class->new(); # good!

可悲的是,现在我不记得/他的原因了。:( 即使构造函数实际上并不存在于 Some::Class 模块中,而是从某处的父级继承,这两种形式都可以正常工作。

这两种形式都与 Some::Class::new() 不同,后者不会将类的名称作为第一个参数传递给构造函数——所以这种形式总是不正确的。

即使这两种形式是等价的,我发现 Some::Class->new() 更清楚,因为它遵循在模块上调用方法的标准约定,而在 perl 中,'new' 方法不是特别 - 构造函数可以被称为任何东西,并且 new() 可以做任何事情(当然我们通常期望它是一个构造函数)。

4

4 回答 4

26

使用new Some::Class被称为“间接”方法调用,这很糟糕,因为它在语法中引入了一些歧义。

它可能失败的一个原因是如果您有一个对象数组或散列。你可能会期待

dosomethingwith $hashref->{obj}

等于

$hashref->{obj}->dosomethingwith();

但它实际上解析为:

$hashref->dosomethingwith->{obj}

这可能不是你想要的。

另一个问题是,如果您的包中恰好有​​一个与您尝试调用的方法同名的函数。例如,如果某个模块您use导出了一个名为 的函数dosomethingwith怎么办?在这种情况下,dosomethingwith $object是模棱两可的,并且可能导致令人费解的错误。

完全使用->语法可以消除这些问题,因为编译器始终清楚方法以及您希望方法操作的内容。

于 2009-01-09T21:23:58.157 回答
21

请参阅perlobj 文档中的间接对象语法以了解其缺陷。freido 的回答涵盖了其中之一(尽管我倾向于在函数调用周围使用明确的括号来避免这种情况)。

Larry 曾经开玩笑说,它的存在是为了让 C++ 感到高兴new,尽管人们会告诉你永远不要使用它,但你可能一直都在使用它。考虑一下:

print FH "Some message";

你有没有想过我的文件句柄后面没有逗号?间接对象​​表示法中的类名后面没有逗号?这就是这里发生的事情。您可以将其重写为 print 上的方法调用:

FH->print( "Some message" );

print如果你做错了,你可能会经历一些奇怪的事情。在显式文件句柄之后放置一个逗号会将其变成一个参数:

print FH, "some message";     # GLOB(0xDEADBEEF)some message

可悲的是,我们在 Perl 中有这种愚蠢。并非语法中的所有内容都是最好的主意,但是当您从众多来源中汲取灵感时,就会发生这种情况。有些想法必须是坏的。

于 2009-01-09T20:49:16.370 回答
4

间接对象​​语法不受欢迎,有充分的理由,但这与构造函数无关。你几乎永远不会在调用包中有一个 new() 函数。相反,您应该使用 Package->new() 有两个(更好?)原因:

  1. 正如你所说,所有其他类方法都采用 Package->method() 的形式,所以一致性是一件好事

  2. 如果您正在向构造函数提供参数,或者您正在获取构造函数的结果并立即在其上调用方法(例如,如果您不关心将对象保留在周围),那么说起来更简单,例如

$foo = Foo->new(type => 'bar', style => 'baz');
Bar->new->do_stuff;

$foo = new Foo(type => 'bar', style => 'baz');
(new Bar)->do_stuff;
于 2009-01-10T00:51:06.130 回答
-3

另一个问题是new Some::Class在运行时发生。如果出现错误并且您的测试永远不会分支到该语句,那么您永远不会知道它,直到它发生在生产中。Some::Class->new除非您正在进行动态编程,否则最好使用。

于 2009-01-10T20:24:35.060 回答