【问题标题】:What is the difference between new Some::Class and Some::Class->new() in Perl?Perl 中的 new Some::Class 和 Some::Class->new() 有什么区别?
【发布时间】:2014-12-07 17:26:41
【问题描述】:

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

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

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

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

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

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

【问题讨论】:

标签: perl methods module


【解决方案1】:

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

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

dosomethingwith $hashref->{obj}

等于

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

但它实际上解析为:

$hashref->dosomethingwith->{obj}

这可能不是你想要的。

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

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

【讨论】:

    【解决方案2】:

    请参阅 perlobj 文档中的 Indirect Object Syntax 以了解其缺陷的解释。 freido's answer 涵盖了其中之一(尽管我倾向于在函数调用周围使用显式括号来避免这种情况)。

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

    print FH "Some message";
    

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

    FH->print( "Some message" );
    

    如果你做错了print,你可能会遇到一些奇怪的事情。在显式文件句柄后加逗号会将其转换为参数:

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

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

    【讨论】:

    • 我已经好几年没读过那个手册页了;我真的应该阅读更多。很遗憾,'new Some::Class' 有很多陷阱,因为我喜欢它的阅读方式比 'Some::Class->new()';我最喜欢 Perl 的一件事是它给人的自然语言感觉。哦,好吧,是时候改变了......
    【解决方案3】:

    间接对象语法不受欢迎,有充分的理由,但这与构造函数无关。你几乎永远不会在调用包中有一个 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;
    

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-10-04
        • 2012-06-30
        • 2015-08-01
        • 2021-09-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-02
        相关资源
        最近更新 更多