我可以在perl中传递对象方法的代码参考吗?

发布于 2025-01-22 20:47:53 字数 623 浏览 0 评论 0原文

在一个网络处理程序中,处理各种参数以获取和设置我正在大量使用。 我有一个子例程,可以接收封闭,并使用返回时作为参数传递的另一个闭合(听起来很复杂,但这只是我想要这样的为什么)。 现在,我有一种情况,我必须通过两个非常相似的封闭,每个封闭情况使用相同的对象方法,但使用不同的参数(对象方法检查传递的参数数)。

我的想法不是通过两个(或更多)类似的封闭,而是将参考$ meth_ref传递给对象的方法(对象也传递给函数返回闭合),以便该函数可以使用代码参考传递不同参数。

不幸的是,我没有发现语法这样做。

代码草图:

sub closure_maker($$)
{
    my ($obj, $meth_ref) = @_;

    return sub (...) {
        $meth_ref->($obj);
        ...
        $meth_ref->($obj, ...);
    };
}

my @handlers = (closure_maker($obj1, ???), closure_maker($obj2, ???));

希望您明白。

In a network handler dealing with various parameters to get and set I'm using closures heavily.
I have a subroutine that receives a closure and builds another closure using that passed as parameter on return (Sounds complicated, but that's just why I want such).
Now I have a case where I would have to pass two very similar closures, each using the same object method, but with different parameters (the object method checks the number of parameters passed).

My idea was not to pass two (or more) similar closures, but pass a reference $meth_ref to the object's method (the object is also passed to the function returning closures), so that the function can use the code reference to pass varying parameters.

Unfortunately I didn't find out the syntax to do so.

Code sketch:

sub closure_maker($)
{
    my ($obj, $meth_ref) = @_;

    return sub (...) {
        $meth_ref->($obj);
        ...
        $meth_ref->($obj, ...);
    };
}

my @handlers = (closure_maker($obj1, ???), closure_maker($obj2, ???));

I hope you get the idea.

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

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

发布评论

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

评论(3

痴骨ら 2025-01-29 20:47:53

使用$ obj--> $ method_name()

sub closure_maker($)
{
    my ($obj, $method_name) = @_;

    return sub {
        $obj->$method_name();
        ...
        $obj->$method_name(...);
    };
}

my @handlers = map { closure_maker($_, "method_name") } $obj1, $obj2;

您可以使用$ obj->可以获得对该方法的引用。

sub closure_maker($)
{
    my ($obj, $method_name) = @_;

    my $method_ref = $obj->can($method_name);

    return sub {
        $obj->$method_ref();
        ...
        $obj->$method_ref(...);
    };
}

Use $obj->$method_name().

sub closure_maker($)
{
    my ($obj, $method_name) = @_;

    return sub {
        $obj->$method_name();
        ...
        $obj->$method_name(...);
    };
}

my @handlers = map { closure_maker($_, "method_name") } $obj1, $obj2;

You can use $obj->can to obtain a reference to the method.

sub closure_maker($)
{
    my ($obj, $method_name) = @_;

    my $method_ref = $obj->can($method_name);

    return sub {
        $obj->$method_ref();
        ...
        $obj->$method_ref(...);
    };
}
装纯掩盖桑 2025-01-29 20:47:53

您可以获取对\& className ::方法的参考,然后可以与该类的给定对象一起使用。例如:

#!/usr/bin/env perl
use strict;
use warnings;
use feature qw/say/;

package Example {
    sub new {
        my ($class, $name) = @_;
        return bless { name => $name }, $class;
    }

    sub method1 {
        my $self = shift;
        say "Method 1 of $self->{name}: @_";
    }
};

sub make_closure($) {
    my ($obj, $method) = @_;
    return sub { $obj->$method(@_); }
}

my $obj1 = Example->new("Bob");
my $obj2 = Example->new("Cindy");
my $closure1 = make_closure($obj1, \&Example::method1);
my $closure2 = make_closure($obj2, \&Example::method1);
$closure1->(qw/1 2/);
$closure2->(qw/A B C/);

输出

Method 1 of Bob: 1 2
Method 1 of Cindy: A B C

如果您是偏执的,则可能需要在方法中添加类型检查,以确保它们不会意外地使用错误类的对象调用。 ISA运算符,在Perl 5.32中添加,使其简单:

# In package Example
use Carp;
sub method1 {
    use experimental qw/isa/;
    my $self = shift;
    croak "Invalid object; should be an Example" unless $self isa Example;
    say "Method 1 of $self->{name}: @_";
}

旧版本可以使用内置isa方法:

# In package Example
use Carp;
use Scalar::Util qw/blessed/;
sub method1 {
    my $self = shift;
    croak "Invalid object; should be an Example"
        unless defined blessed $self && $self->isa("Example");
    say "Method 1 of $self->{name}: @_";
}

You can get a reference to a method with \&Classname::method that can then be used with a given object of that class. For example:

#!/usr/bin/env perl
use strict;
use warnings;
use feature qw/say/;

package Example {
    sub new {
        my ($class, $name) = @_;
        return bless { name => $name }, $class;
    }

    sub method1 {
        my $self = shift;
        say "Method 1 of $self->{name}: @_";
    }
};

sub make_closure($) {
    my ($obj, $method) = @_;
    return sub { $obj->$method(@_); }
}

my $obj1 = Example->new("Bob");
my $obj2 = Example->new("Cindy");
my $closure1 = make_closure($obj1, \&Example::method1);
my $closure2 = make_closure($obj2, \&Example::method1);
$closure1->(qw/1 2/);
$closure2->(qw/A B C/);

outputs

Method 1 of Bob: 1 2
Method 1 of Cindy: A B C

If you're paranoid, you might want to add type checking to the methods to make sure they're not accidentally called with an object of the wrong class. The isa operator, added in perl 5.32, makes this easy:

# In package Example
use Carp;
sub method1 {
    use experimental qw/isa/;
    my $self = shift;
    croak "Invalid object; should be an Example" unless $self isa Example;
    say "Method 1 of $self->{name}: @_";
}

Older versions can use the built-in isa method:

# In package Example
use Carp;
use Scalar::Util qw/blessed/;
sub method1 {
    my $self = shift;
    croak "Invalid object; should be an Example"
        unless defined blessed $self && $self->isa("Example");
    say "Method 1 of $self->{name}: @_";
}
等待圉鍢 2025-01-29 20:47:53

我找到了一个确实很丑陋的解决方案,但它起作用。
示例会话来自真实代码:

### this is the sample method:
  DB<5> x MessageLogFormat::log_appname($log_format)
0  ''
  DB<11> $xxxx = \&{*{MessageLogFormat::log_appname}}

  DB<12> x ref $xxxx
0  'CODE'
  DB<13> x $xxxx->($log_format)
0  ''
  DB<14> x $xxxx->($log_format, 1)
0  1
### NAME() just outputs the name of the class
  DB<17> $n = $log_format->NAME()
  DB<19> $xxx = \&{*{${n}.'::log_appname'}}
### the method is actually a closure (provided by class `Class`) by itself
  DB<20> x $xxx
0  CODE(0x1af8960)
   -> &Class::__ANON__[lib/Class.pm:85] in lib/Class.pm:78-85
  DB<21> x $xxx->($log_format)
0  1
  DB<22> x $xxx->($log_format, 0)
0  ''
  DB<23> x $xxx->($log_format)
0  ''
### So that worked; try a non-closure method, too:
  DB<24> $xxx = \&{*{${n}.'::new'}}
  DB<25> x $xxx
0  CODE(0x1afcb88)
   -> &MessageLogFormat::new in lib/MessageLogFormat.pm:85-91

在绘制的解决方案中,我不必知道(并明确写下)所使用的每个对象的类。

I found a solution that is really ugly, but it works.
The sample session is from the real code:

### this is the sample method:
  DB<5> x MessageLogFormat::log_appname($log_format)
0  ''
  DB<11> $xxxx = \&{*{MessageLogFormat::log_appname}}

  DB<12> x ref $xxxx
0  'CODE'
  DB<13> x $xxxx->($log_format)
0  ''
  DB<14> x $xxxx->($log_format, 1)
0  1
### NAME() just outputs the name of the class
  DB<17> $n = $log_format->NAME()
  DB<19> $xxx = \&{*{${n}.'::log_appname'}}
### the method is actually a closure (provided by class `Class`) by itself
  DB<20> x $xxx
0  CODE(0x1af8960)
   -> &Class::__ANON__[lib/Class.pm:85] in lib/Class.pm:78-85
  DB<21> x $xxx->($log_format)
0  1
  DB<22> x $xxx->($log_format, 0)
0  ''
  DB<23> x $xxx->($log_format)
0  ''
### So that worked; try a non-closure method, too:
  DB<24> $xxx = \&{*{${n}.'::new'}}
  DB<25> x $xxx
0  CODE(0x1afcb88)
   -> &MessageLogFormat::new in lib/MessageLogFormat.pm:85-91

In the solution sketched I don't have to know (and write down explicitly) the class of each object being used.

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