在 Perl 中,如何调用名称在字符串中的方法?

发布于 2024-08-31 02:53:22 字数 818 浏览 6 评论 0原文

我正在尝试编写一些抽象代码,用于在相似对象列表中搜索第一个属性与特定值匹配的对象。为了做到这一点,我需要调用一堆访问器方法并一一检查它们的所有值。我想使用这样的抽象:

sub verify_attribute {
    my ($object, $attribute_method, $wanted_value) = @_;
    if ( call_method($object, $attribute_method) ~~ $wanted_value ) {
        return 1;
    }
    else {
        return;
    }
}

然后我可以循环遍历一个哈希,其键是访问器方法名称,其值是我正在寻找这些属性的值。例如,如果该哈希名为 %wanted,我可能会使用这样的代码来查找我想要的对象:

my $found_object;
FINDOBJ: foreach my $obj (@list_of_objects) {
    foreach my $accessor (keys %wanted) {
        next FINDOBJ unless verify_attribute($obj, $accessor, $wanted{$accessor});
    }
    # All attrs verified
    $found_object = $obj;
    last FINDOBJ;
}

当然,唯一的问题是 call_method 不存在。或者确实如此?如果我有一个包含方法名称的字符串,如何调用该方法?或者有更好的解决方案来解决整个问题吗?

I'm trying to write some abstract code for searching through a list of similar objects for the first one whose attributes match specific values. In order to do this, I need to call a bunch of accessor methods and check all their values one by one. I'd like to use an abstraction like this:

sub verify_attribute {
    my ($object, $attribute_method, $wanted_value) = @_;
    if ( call_method($object, $attribute_method) ~~ $wanted_value ) {
        return 1;
    }
    else {
        return;
    }
}

Then I can loop through a hash whose keys are accessor method names and whose values are the values I'm looking for for those attributes. For example, if that hash is called %wanted, I might use code like this to find the object I want:

my $found_object;
FINDOBJ: foreach my $obj (@list_of_objects) {
    foreach my $accessor (keys %wanted) {
        next FINDOBJ unless verify_attribute($obj, $accessor, $wanted{$accessor});
    }
    # All attrs verified
    $found_object = $obj;
    last FINDOBJ;
}

Of course, the only problem is that call_method does not exsit. Or does it? How can I call a method if I have a string containing its name? Or is there a better solution to this whole problem?

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

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

发布评论

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

评论(2

时光无声 2024-09-07 02:53:22
my $found_object;
FINDOBJ: foreach my $obj (@list_of_objects) {
  foreach my $accessor (keys %wanted) {
    next FINDOBJ unless $obj->$accessor() == $wanted{$accessor};
  }
  # All attrs verified
  $found_object = $obj;
  last;
}

是的,您可以通过这种方式调用方法。不涉及字符串(或任何其他)评估。
另外,根据数据的类型,用 eq=~ 替换 ==...

或者,为了获得一些额外的积分,可以这样做功能方式:(all()确实应该是List::Util的一部分!)

use List::Util 'first';

sub all (&@) {
  my $code = shift;
  $code->($_) || return 0 for @_;
  return 1;
}

my $match = first {
                    my $obj = $_;
                    all { $obj->$_ == $attrs{$_} }
                      keys %wanted
                  } @list_of_objects;

更新:诚然,第一个解决方案是不太混乱的解决方案,所以它是更好的选择。但作为回答问题的人,你也添加了一点糖,让自己变得有趣! ;-)

my $found_object;
FINDOBJ: foreach my $obj (@list_of_objects) {
  foreach my $accessor (keys %wanted) {
    next FINDOBJ unless $obj->$accessor() == $wanted{$accessor};
  }
  # All attrs verified
  $found_object = $obj;
  last;
}

Yes, you can call methods this way. No string (or any other) eval involved.
Also, substitute == with eq or =~ depending on the type of the data...

Or, for some extra credits, do it the functional way: (all() should really be part of List::Util!)

use List::Util 'first';

sub all (&@) {
  my $code = shift;
  $code->($_) || return 0 for @_;
  return 1;
}

my $match = first {
                    my $obj = $_;
                    all { $obj->$_ == $attrs{$_} }
                      keys %wanted
                  } @list_of_objects;

Update: Admittedly, the first solution is the less obfuscated one, so it's preferable. But as somebody answering questions, you have add a little sugar to make it interesting for yourself, too! ;-)

暮年慕年 2024-09-07 02:53:22

函数式方式很酷,但对于像我这样的傻瓜来说评估规则:

test.pl

#!/usr/bin/perl -l
use F;
my $f = F->new();

my $fun = 'lol'; # method of F

eval '$f->'.$fun.'() '; # call method of F, which name is in $fun var

F.pm

package F;

sub new
{
    bless {};
}


sub lol
{
    print "LoL";
}
1;

[root@ALT-24 root]# perl test.pl

LoL

Functional way is cool, but for dummies like me eval rules:

test.pl

#!/usr/bin/perl -l
use F;
my $f = F->new();

my $fun = 'lol'; # method of F

eval '$f->'.$fun.'() '; # call method of F, which name is in $fun var

F.pm

package F;

sub new
{
    bless {};
}


sub lol
{
    print "LoL";
}
1;

[root@ALT-24 root]# perl test.pl

LoL

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