在Perl中,创建一个与包名称相同的子例程有什么危害吗?

时间:2011-05-24 20:17:27

标签: perl syntax constructor

假设我有一个名为My::Pkg的包,并且该包具有->new(...)类方法来实例化新对象:

package My::Pkg;

sub new {bless {@_[1..$#_]} => $_[0]}

定义以下子程序是否有任何危害:

sub My::Pkg {@_ ? My::Pkg::new('My::Pkg', @_) : 'My::Pkg'}

所以有人可以写:

my $obj = My::Pkg one => 1, two => 2;

而不是:

my $obj = My::Pkg->new(one => 1, two => 2); # which still works, but is longer

我喜欢package-named-constructor-subroutine方法的简洁性,但我很想知道这项技术是否有任何隐藏的问题,我没有想过。


更新

继承正常工作,如下例所示:

{package a; sub new {say "a::new [@_] ", $_[0]->init}}
{package b;    our @ISA = 'a'; sub init {"(b::init [@_])"}}
{package a::b; our @ISA = 'b';}

sub a::b {print "absub [@_], "; 'a::b'}

# a::b() called with no args, returns 'a::b', which then becomes 'a::b'->new(...)
a::b->new;            # absub [], a::new [a::b] (b::init [a::b])
a::b->new(1, 2, 3);   # absub [], a::new [a::b 1 2 3] (b::init [a::b])    

# no call to `a::b()` but otherwise the same:
'a::b'->new;          # a::new [a::b] (b::init [a::b])
'a::b'->new(1, 2, 3); # a::new [a::b 1 2 3] (b::init [a::b])

new a::b::;           # a::new [a::b] (b::init [a::b])
new a::b:: 1, 2, 3;   # a::new [a::b 1 2 3] (b::init [a::b])

有趣的是,到目前为止唯一不同的是以下两行成为语法错误:

new a::b;
new a::b 1, 2, 3;

出于同样的原因some_undefined_sub some_defined_sub;是一个语法错误。

如果定义了new子例程,则将其解析为new( a::b(...) ),这对于两个相邻的裸字子例程是正常的。

就个人而言,我很好new a::b成为语法错误,明确的版本new a::b::将始终有效,因为 tchrist 有助于指出以下内容。

2 个答案:

答案 0 :(得分:7)

正是为什么

$thingie = new Some::Class one => 1, two => 2;

$thingie = new Some::Class::
               one => 1,
               two => 2,
           ;

存在,所以只需使用它。

但是,是的,我认为你会陷入一大堆麻烦,因为我是世界上唯一一个无法打包报价的人。我现在没有时间深入挖掘我的旧问题测试代码,但我很确定如果你走的是你所说的话,这最终会让你哭泣。

答案 1 :(得分:4)

“我很想知道这项技术是否有任何隐藏的问题,我没有想过。”

我认为隐藏的问题与大多数OOP langs定义构造函数的方式缺乏一致性。显然,Perl喜欢它的TMTOWTDI理念,但有些人必须在以后/如果你不在的时候维护你的代码可能需要更多的时间来理解你的代码在做什么。

另外,如果你想添加另一个构造函数怎么办?我已经看到了一些类,其中有构造函数名称:new,new_from_file等。也许不是最好的设计,但它确实澄清了一个对象是以一种独特的方式构建的。