我在类中有方法,我需要确保只在对象实例上调用,而不是作为类方法.
我可能会做这样的事情:
# Edit: this is terrible, don't do this, it breaks inheritance.
sub foo
{
my ($self) = @_;
if (ref($self) ne __PACKAGE__) { return; }
...do stuff
}
Run Code Online (Sandbox Code Playgroud)
但我认为这样做会更有效:
sub foo
{
my ($self) = @_;
if (not ref($self)) { return; }
...do stuff
}
Run Code Online (Sandbox Code Playgroud)
问题:
是否可以安全地假设如果ref()返回不是undef,它将返回当前包?
理想情况下,我希望在我的所有方法中重新检查并执行类似的操作.这是个坏主意吗?
有没有更美好的方式来做我想要的?
在这种情况下,"使用驼鹿"不是一个可接受的答案.但是,如果您不得不这样说,请告诉我moose如何使这简单或更有效.我可能想将它合并到我自己的对象系统中.
谢谢!
编辑以反映ref永远不会返回undef,只是一个空字符串.
编辑2这是一个后续问题.以下有人建议使用:
$self->isa(__PACKAGE__)
Run Code Online (Sandbox Code Playgroud)
但这不会总能成功吗?当然除非呼叫者做了一些真正愚蠢的事情:
MyClass::MyMethod($ref_to_some_other_object)
Run Code Online (Sandbox Code Playgroud)
首先,你可能不应该croak默默地做任何事情,因为根据你的规范,调用foo类方法是违反合同的.
其次,只检查第一个参数是否是参考就足够了.如果涉及继承,您的方法将失败:
#!/usr/bin/perl
package A;
use Carp;
sub new { bless {} => shift }
sub foo {
croak "I am not in " . __PACKAGE__ unless __PACKAGE__ eq ref(shift)
}
package B;
use base 'A';
package main;
$x = B->new;
$x->foo;
Run Code Online (Sandbox Code Playgroud)
C:\Temp> t I am not in A at C:\Temp\t.pl line 19
如果引用的对象已被保存到包中,则返回该包名称.您可以将其
ref视为typeof运营商.
所以:
sub foo {
croak "Don't call as class method" unless ref shift;
}
Run Code Online (Sandbox Code Playgroud)
最后,请注意ref 永远不会返回undef.
将此检查添加到每个方法都是一个好主意吗?我猜一个人可以通过契约观点从设计中得出这个论点.
另一方面,我的方法假设它们被称为实例方法,并且我只检查方法被调用为类方法的可能性,如果该方法在被调用时可以提供有意义的替代行为.
我不记得任何有这些检查的模块.
顺便说一句,而不是
sub foo {
my ($self) = @_;
Run Code Online (Sandbox Code Playgroud)
你应该使用
sub foo {
my $self = shift;
Run Code Online (Sandbox Code Playgroud)
只留下方法中的参数@_进行解包.或者,您应该一举解压所有参数:
sub foo {
my ($self, $bar, $baz) = @_;
Run Code Online (Sandbox Code Playgroud)