寻找 Perl 习惯用法来检查 $self 是一个类还是一个对象 [英] Seek Perl idiom to check that $self is a class or object

查看:78
本文介绍了寻找 Perl 习惯用法来检查 $self 是一个类还是一个对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Perl 中,我刚刚被类似于下面的错误的东西咬了一口:

In Perl, I just got bitten by something that looked like the bug below:

package Foo;
sub method {
    my $self = shift;
    my @args = @_;
    ...
}

我把它称为子程序,而不是方法:

where I called it as a subroutine, not a method:

Foo::method( "arg1", "arg2" );

而不是将其作为方法调用 - 在这种情况下,它是一个类方法":

rather than calling it as a method - in this case, it was a "class method":

Foo->method( "arg1", "arg2" );

调用 Foo::method("arg1","arg2") 导致arg1"被丢弃.

Calling Foo::method("arg1","arg2") resulted in "arg1" getting dropped.

对象方法"可能会出现类似的考虑:

Similar considerations can arise with an "object method":

my $object = Foo->new();
$obj->method( "arg1", "arg2" );

是否有一种友好、简洁的 Perl 习惯用法来检查第一个参数,通常称为 $self,实际上是类(包)和/或类/包中的对象名字?

Is there a friendly, concise, Perl idiom for checking that the first argument, conventionally called $self, is in fact an object in the class (package), and/or the class/package name?

我想出的最好的是:

package Foo;
sub method {
    my $self = ($_[0]->isa(__PACKAGE__) ? shift @_ : die "...error message...";
    my @args = @_;
    ...
}

这并不比

package Foo;
sub method {
    my $self = shift;
    die "...error message..."  if $self->isa(__PACKAGE__);
    my @args = @_;
    ...
}

package Foo;
use Carp::Assert;
sub method {
    my $self = shift;
    assert($self->isa(__PACKAGE__));
    my @args = @_;
    ...
}

<小时>

注意事项:


Notes:

我了解 Perl 签名,但不喜欢使用实验性功能.

I know about Perl signatures, but dislike using experimental features.

我知道使用属性:method.这是最好的方式吗?对不断发展的"功能的类似担忧.

I know about use attributes and :method. Is that the best way to go? Similar concerns about "evolving" features.

我知道 Moose - 但我不认为 Moose 会强制执行此操作.(我是不是错过了什么.)

I know about Moose - but I don't think that Moose enforces this. (Did I miss anything.)

Perl 的问题在于有很多方法可以做某事.

The problem with Perl is that there are so many ways to do something.

推荐答案

最好的答案是不要在一个包中混合函数和方法.众所周知,混合模块"是有问题的.您可能想要创建函数的所有内容都应该是类方法调用.

The best answer is to not mix functions and methods in a single package. "Hybrid modules", as they're known, are problematic. Everything which you might want to make a function should instead be a class method call.

在日常编程中应该几乎不需要完全限定函数调用.

There should be little need to fully qualify a function call in day-to-day programming.

最简洁的方法是使用 Moops 这是使用 Moose 语法的新方法-糖.

The most concise way is to use Moops which is the new way to use Moose with syntax-sugar.

use Moops;

class Foo {
    method something() {
        print("something called\n");
    }
}

Foo->new->something();
Foo::something();

# something called
# Invocant $self is required at /Users/schwern/tmp/test.plx line 10.

Moops 被标记为不稳定,但这是界面,而不是签名本身.签名已经存在并在生产中使用了很长时间,比它们内置的时间更长.更令人担忧的是已经有一年多没有发布了,但是作者写了好东西.您的来电.

Moops is marked as unstable, but that's the interface, not the signatures themselves. Signatures have been around and usable in production for a long time, longer than they've been built in. More worrying is there hasn't been a release in over a year, however the author writes good stuff. Your call.

否则,就像其他任何事情一样,编写一个函数.

Otherwise, like with anything else, write a function.

use Carp;
use Scalar::Util qw(blessed);

sub check_invocant {
    my $thing = shift;

    my $caller = caller;

    if( !defined $thing ) {
        croak "The invocant is not defined";
    }
    elsif( !ref $thing ) {
        croak "The invocant is not a reference";
    }
    elsif( !blessed $thing ) {
        croak "The invocant is not an object";
    }
    elsif( !$thing->isa($caller) ) {
        croak "The invocant is not a subclass of $caller";
    }

    return $thing;
}

由于这会返回调用者并为您处理异常,因此可以非常简洁地使用.

Since this returns the invocant and handles the exception for you it can be used very concisely.

package Foo;

sub method {
    my $self = ::check_invocant(shift);

    ...
}

这篇关于寻找 Perl 习惯用法来检查 $self 是一个类还是一个对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆