【问题标题】:Perl - call an instance of a classPerl - 调用类的实例
【发布时间】:2017-12-10 21:26:46
【问题描述】:

有没有办法捕捉调用 Perl 类实例的事件?

my $obj = ExampleClass->new();
$obj(); # do something without producing error

我希望能够在类/模块定义中处理这个问题。类似于 Python 中的 __call__ 方法或 Lua 中的 __call 元方法。

【问题讨论】:

  • “调用实例”是什么意思?请注意,$obj() 是 Perl 中的语法错误。
  • 短语“类实例”通常表示“对象”。但是不能“调用它”,您通常使用它来调用类中定义的方法。这不会引发“事件”(不会在任何地方发送通知)。如果您打算在使用对象时使事情发生,您可以这样做,但重要的是您的真正意思和想要做什么。请澄清问题,解释得更好。
  • 类似于 Python 中的 __call__ 函数,或 Lua 中的 __call 元方法。

标签: function perl class call instance


【解决方案1】:

我仍然不确定用例是什么,但您可以overload 类来处理代码取消引用。

package ExampleClass;
use overload '&{}' => \&__call__;   # Or an anon sub.
sub new {
   bless {@_}, shift;
}
sub __call__ {
    sub { warn "calling an instance event" };
}

package main;
my $obj = ExampleClass->new;
$obj->();
&$obj();      # same as $obj->()

典型输出:

$ perl 44956235.pl
calling an instance event at 44956235.pl line 7.
calling an instance event at 44956235.pl line 7.

【讨论】:

  • 我收到一个错误:Overloading the dereference did not return a reference 使用此功能时(输入__call__ 函数后)。任何想法为什么?
  • 重载解引用函数应该返回适​​当类型的引用。我已经更新了我的答案。
【解决方案2】:

Overloading "&{}" 显然是要走的路,但您可以将对象基于 sub 而不是通常首选的哈希。

ExampleClass.pm:

package ExampleClass;

use strict;
use warnings;
use feature qw( current_sub say );

my %objects;

sub new {
   my $class = shift;
   my $dummy;  # Force each evaluation of sub{} to return a new variable.
   my $self = bless(sub { $dummy if 0; __SUB__ ->__call__(@_) }, $class) }, $class);
   my $inner = $objects{$self} = {};
   return $self;
}

sub DESTROY {
   my $self = shift;
   delete($objects{$self});
}

sub __call__ {
   my $inner = $objects{ my $self = shift };
   say "__call__(".join(", ", @_).")";
}

sub some_attribute {
   my $inner = $objects{ my $self = shift };
   if (@_) { $inner->{some_attribute} = $_[0]; }
   return $inner->{some_attribute};
}

1;

主程序:

#!/usr/bin/perl

use strict;
use warnings;
use feature qw( say );

use ExampleClass qw( );

{
   my $obj = ExampleClass->new();

   $obj->some_attribute("value");
   say $obj->some_attribute();

   $obj->(qw( a b c ));
}

{
   my $obj1 = ExampleClass->new();
   $obj1->some_attribute("value1");

   my $obj2 = ExampleClass->new();
   $obj2->some_attribute("value2");

   say $obj1->some_attribute();
   say $obj2->some_attribute();
}

输出:

value
__call__(a, b, c)
value1
value2

这基本上就是所谓的“由内而外”的对象。

【讨论】:

  • 这太迷人了。
  • @zdim,可以使用 PadWalker 访问 $dummy 并将胆量存储在那里而不是全局哈希 :)
【解决方案3】:

您正在寻找的东西称为函子。您可以创建一个基类来更轻松地实现您的仿函数。例如:

package AbstractFunctorObject;
use strict;
use warnings;
use overload '&{}' => sub { $_[0]->can( '__invoke' ) };

sub new
{
  my $class = shift;
  bless { @_ }, $class;
}

1;
__END__

然后,您可以按如下方式实现您的函子:

package FunctorObject;
use strict;
use warnings;
use parent 'AbstractFunctorObject';

sub __invoke
{
  print "Called as a functor with args: @{ [ @_ ? @_ : 'no argument given' ] }\n";
}

1;
__END__

最后,您可以按如下方式调用函子:

package main;
use FunctorObject;

my $functor = FunctorObject->new();
$functor->('firstname', 'lastname');
$functor->();

结果将是:

root@jessie:/usr/local/src# perl callable_object.pl 
Called as a functor with args: firstname lastname
Called as a functor with args: no argument given

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-20
    • 2015-06-10
    • 2015-12-04
    • 2021-08-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多