12

我只是讨厌如何调用CGI::ApplicationCGI对象访问器query

我希望我的实例类能够使用名为的访问器cgi来获取CGI与我的子类的当前实例关联的对象CGI::Application

这是我正在做的一个独立的例子:

package My::Hello;

sub hello {
    my $self =shift;
    print "Hello @_\n";
}

package My::Merhaba;

use base 'My::Hello';

sub merhaba {
    goto sub { shift->hello(@_) };
}

package main;

My::Merhaba->merhaba('StackOverflow');

这是我认为应该的工作,我看不到任何问题(例如,如果我想继承自My::Merhaba: 子类不需要知道任何关于 的内容merhaba)。

写起来会更好/更正确吗

sub merhaba {
    my $self = shift;
    return $self->hello(@_);
}

goto &NAME为方法名称起别名而使用的优点/缺点是什么?有没有更好的办法?

注意:如果你有反应goto是邪恶的冲动,不要这样做,因为 Perl 的这种用法与goto你的想法不同。

4

4 回答 4

10

您的方法goto是正确的,因为它将确保caller/wantarray等保持正常工作。

我会像这样设置新方法:

sub merhaba {
    if (my $method = eval {$_[0]->can('hello')}) {
        goto &$method
    } else { 
        # error code here
    }
}

或者,如果您不想使用继承,您可以从调用代码中将新方法添加到现有包中:

*My::Hello::merhaba = \&My::Hello::hello;  
   # or you can use = My::Hello->can('hello');

然后你可以打电话:

My::Hello->merhaba('StackOverflow');

并得到想要的结果。

无论哪种方式都可以,继承路由更易于维护,但是将方法添加到现有包中会导致更快的方法调用。

编辑:

正如评论中所指出的,在某些情况下,全局分配会与继承发生冲突,因此如果有疑问,请使用第一种方法(在子包中创建新方法)。

Michael Carman 建议将这两种技术结合到一个自我重新定义的功能中:

sub merhaba {
    if (my $method = eval { $_[0]->can('hello') }) {
        no warnings 'redefine';
        *merhaba = $method;
        goto &merhaba;
    }
    die "Can't make 'merhaba' an alias for 'hello'";
}
于 2010-02-15T16:54:47.590 回答
3

您可以通过操作符号表来给子例程起别名:

*My::Merhaba::merhaba = \&My::Hello::hello;

一些例子可以在这里找到。

于 2010-02-15T15:30:58.387 回答
2

我不确定正确的方法是什么,但 Adam Kennedy在Method::Aliasgoto中使用了您的第二种方法(即不使用)(单击此处直接转到源代码)。

于 2010-02-15T17:53:47.830 回答
1

这是 Quick-n-Dirty 与少量间接使用的组合UNIVERSAL::can

package My::Merhaba;
use base 'My::Hello';
# ...
*merhaba = __PACKAGE__->can( 'hello' );

你会在这个包中有一个名为“merhaba”的子别名My::Hello::hello。您只是在说这个包在 namehello下可以做的任何事情,它可以在 name 下做merhaba

但是,这还不够,因为某些代码装饰器可能会更改*My::Hello::hello{CODE}指向的 sub。在这种情况下Method::Alias,正如分子所暗示的那样,可能是指定方法的适当方式。

但是,如果它是一个控制良好的库,您可以同时控制父类别和子类别,那么上面的方法是slimmmer

于 2010-02-15T21:01:07.577 回答