在 Perl 中,创建与包同名的子例程有什么坏处吗?
假设我有一个名为 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_define_sub;
是一。
如果定义了 new 子例程,它将被解析为 new( a::b(...) ) ,这对于两个相邻的裸字子例程来说是正常的。
就我个人而言,我同意 new a::b
成为语法错误,明确的版本 new a::b::
将始终以 tchrist 的方式工作em> 下面有帮助地指出。
Say I have a package called My::Pkg
, and that package has a ->new(...)
class method to instantiate new objects:
package My::Pkg;
sub new {bless {@_[1..$#_]} => $_[0]}
Is there any harm in defining the following subroutine:
sub My::Pkg {@_ ? My::Pkg::new('My::Pkg', @_) : 'My::Pkg'}
So that someone could write:
my $obj = My::Pkg one => 1, two => 2;
Rather than:
my $obj = My::Pkg->new(one => 1, two => 2); # which still works, but is longer
I like the terseness of the package-named-constructor-subroutine method, but I am interested to know if there are any hidden gotchas to this technique that I have not thought of.
Update:
Inheritance works correctly, as shown by the example here:
{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])
Interestingly the only thing so far that is different is that the following 2 lines become syntax errors:
new a::b;
new a::b 1, 2, 3;
Which is a syntax error for the same reason some_undefined_sub some_defined_sub;
is one.
If the new
subroutine is defined, it is parsed as new( a::b(...) )
which is normal for two adjacent bareword subroutines.
Personally, I am ok with new a::b
becoming a syntax error, the unambiguous version new a::b::
will always work as tchrist helpfully points out below.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这正是
或
存在的原因,所以只需使用它即可。
但是,是的,我认为你会给自己带来一大堆麻烦,因为我是世界上唯一一个费心打包报价的人。我现在没有时间深入研究我的旧问题测试代码,但我很确定,如果您沿着您所说的道路走下去,这最终会让您哭泣。
That’s precisely why
or
exists, so just use that.
But yes, I think you will get yourself into a whole slew of troubles, since I am the only person in the world who bothers to package-quote. I don’t have time right now to dig through my old problem-testing code, but I am pretty sure this will eventually make you cry if you go down the road you’re speaking of.
“我很想知道这项技术是否存在我没有想到的隐藏问题。”
我认为一个隐藏的问题是与大多数 OOP 语言定义构造函数的方式缺乏一致性。显然,Perl 喜欢它的 TMTOWTDI 哲学,但是当/如果你不在身边时,有人必须稍后维护你的代码,可能需要更多时间来理解你的代码在做什么。
另外,如果你想添加另一个构造函数怎么办?我见过一些类,其中有名为:new、new_from_file 等的构造函数。也许不是最好的设计,但它确实阐明了对象是以独特的方式构造的。
"I am interested to know if there are any hidden gotchas to this technique that I have not thought of."
I think a hidden gotcha is lack of consistency with how most OOP langs define constructors. Obviously, Perl likes its TMTOWTDI philosophy, but someone having to maintain your code later when/if you're not around may take more time to understand what your code is doing.
Also, what if you want to add another constructor? I've seen some classes where there are constructors named: new, new_from_file, etc. Maybe not the best design, but it did clarify that an object was constructed in a unique way.