在 Perl 中,子类为基类中的方法添加别名的正确方法是什么?

发布于 2024-08-21 18:55:59 字数 1104 浏览 5 评论 0原文

我只是讨厌 CGI::ApplicationCGI< 访问器/code> 对象称为查询

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

这是我正在做的事情的一个独立示例:

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(@_);
}

写一下What are the Advantages/disadvantages of using goto & ;NAME 是为了给方法名起别名吗?有更好的办法吗?

注意:如果您想用 goto 进行响应,goto 是邪恶的,请不要这样做,因为 Perl 的 goto 的使用code> 与您的想法不同。

I simply hate how CGI::Application's accessor for the CGI object is called query.

I would like my instance classes to be able to use an accessor named cgi to get the CGI object associated with the current instance of my CGI::Application subclass.

Here is a self-contained example of what I am doing:

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');

This is working as I think it should and I cannot see any problems (say, if I wanted to inherit from My::Merhaba: Subclasses need not know anything about merhaba).

Would it have been better/more correct to write

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

What are the advantages/disadvantages of using goto &NAME for the purpose of aliasing a method name? Is there a better way?

Note: If you have an urge to respond with goto is evil don't do it because this use of Perl's goto is different than what you have in mind.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

两仪 2024-08-28 18:55:59

您使用 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');

并获得所需的结果。

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

编辑:

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

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'";
}

Your approach with goto is the right one, because it will ensure that caller / wantarray and the like keep working properly.

I would setup the new method like this:

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

Or if you don't want to use inheritance, you can add the new method to the existing package from your calling code:

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

then you can call:

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

and get the desired result.

Either way would work, the inheritance route is more maintainable, but adding the method to the existing package would result in faster method calls.

Edit:

As pointed out in the comments, there are a few cases were the glob assignment will run afoul with inheritance, so if in doubt, use the first method (creating a new method in a sub package).

Michael Carman suggested combining both techniques into a self redefining function:

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'";
}
尹雨沫 2024-08-28 18:55:59

您可以通过操作符号表为子例程设置别名:

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

可以找到一些示例

You can alias the subroutines by manipulating the symbol table:

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

Some examples can be found here.

这样的小城市 2024-08-28 18:55:59

我不确定正确的方法是什么,但 Adam Kennedy 在 方法::别名 (点击这里直接进入源码)。

I'm not sure what the right way is, but Adam Kennedy uses your second method (i.e. without goto) in Method::Alias (click here to go directly to the source code).

半窗疏影 2024-08-28 18:55:59

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

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

在这个包中您将有一个名为“merhaba”的子项目,它的别名是 My::Hello::hello。您只是说,无论这个包在 hello 名称下执行的操作,它都可以在 merhaba 名称下执行。

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

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

This is sort of a combination of Quick-n-Dirty with a modicum of indirection using UNIVERSAL::can.

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

And you'll have a sub called "merhaba" in this package that aliases My::Hello::hello. You are simply saying that whatever this package would otherwise do under the name hello it can do under the name merhaba.

However, this is insufficient in the possibility that some code decorator might change the sub that *My::Hello::hello{CODE} points to. In that case, Method::Alias might be the appropriate way to specify a method, as molecules suggests.

However, if it is a rather well-controlled library where you control both the parent and child categories, then the method above is slimmmer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文