gpt4 book ai didi

perl - 在 perl 中向现有对象添加新方法

转载 作者:行者123 更新时间:2023-12-04 17:34:23 27 4
gpt4 key购买 nike

我有这个 perl 对象。在对象被实例化后,我试图在加载器方法中向对象添加一个新方法,然后可以稍后调用。

我已经尝试了一大堆没有用的东西。示例包括:

sub loader {
my ($self) = @_;

sub add_me {
my ($self, $rec) = @_

warn "yayyyyyy";
return $rec;
}

#here are the things I've tried that dont work:
# &{$self->{add_me}} = \&add_me;
# \&{$self->{add_me}} = \&add_me;
# assuming the class definition is in Holder::Class try to add it to symblol table
# *{Holder::Class::add_me} = \&add_me;

}

编辑:

我需要这样做的原因是我在我的代码中添加了一个钩子(Hook),我的软件的用户将能够注入(inject)他们自己的 sub 来编辑数据结构。

为此,他们将能够编辑一个仅包含一个子文件的辅助文件,并获取传入的相关数据结构,例如:
sub inject_a_sub {
my ($self, $rec) = @_;

#do stuff to $rec

return $rec;
}

然后在实例化的原始对象中,我检查上述文件是否存在,如果存在,则读取其内容并评估它们。最后,我想制作 eval 的代码,它只是一个 sub,我的对象的一个​​方法。准确地说,我的对象已经继承了一个名为 do_something 的方法。我想让 eval 读取的 sub 覆盖 do_something方法被继承,以便在从外部文件调用 sub 时运行。

这是一个奇怪的问题:/

它伤害了我:(

Obi wan kenobi 你是我唯一的希望!

干杯!

最佳答案

如果您只想将功能附加到特定对象,并且不需要继承,则可以在对象中存储代码引用并调用它。

# Store the code in the object, putting it in its own
# nested hash to reduce the chance of collisions.
$obj->{__actions}{something} = sub { ... };

# Run the code
my @stuff = $obj->{__actions}{something}->(@args);

问题是,您需要检查 $obj->{__actions}{something}包含代码引用。我的建议是围绕这个过程包装一个方法。
sub add_action {
my($self, $action, $code) = @_;

$self->{__actions}{$action} = $code;

return;
}

sub take_action {
my($self, $action, $args) = @_;

my $code = $self->{__actions}{$action};
return if !$code or ref $code ne 'CODE';

return $code->(@$args);
}

$obj->add_action( "something", sub { ... } );
$obj->take_action( "something", \@args );

如果您已经知道要将方法注入(inject)的类名,请照常编写子例程,但使用完全限定名。
sub Some::Class::new_method {
my $self = shift;

...
}

请注意,该子例程中的任何全局变量都将在周围的包中,而不是在 Some::Class 中。如果您想要持久变量,请使用 state在子程序内或 my在子程序之外。

如果您在编译时不知道名称,则必须将子例程注入(inject)符号表,因此您与最后一个很接近。
sub inject_method {
my($object, $method_name, $code_ref) = @_;

# Get the class of the object
my $class = ref $object;

{
# We need to use symbolic references.
no strict 'refs';

# Shove the code reference into the class' symbol table.
*{$class.'::'.$method_name} = $code_ref;
}

return;
}

inject_method($obj, "new_method", sub { ... });

Perl 中的方法与一个类相关联,而不是与一个对象相关联。为了将方法分配给单个对象,您必须将该对象放入其自己的类中。与上面类似,但您必须为每个实例创建一个子类。
my $instance_class = "_SPECIAL_INSTANCE_CLASS_";
my $instance_class_increment = "AAAAAAAAAAAAAAAAAA";
sub inject_method_into_instance {
my($object, $method_name, $code_ref) = @_;

# Get the class of the object
my $old_class = ref $object;

# Get the special instance class and increment it.
# Yes, incrementing works on strings.
my $new_class = $instance_class . '::' . $instance_class_increment++;

{
# We need to use symbolic references.
no strict 'refs';

# Create its own subclass
@{$new_class.'::ISA'} = ($old_class);

# Shove the code reference into the class' symbol table.
*{$new_class.'::'.$method_name} = $code_ref;

# Rebless the object to its own subclass
bless $object, $new_class;
}

return;
}

我省略了代码来检查实例是否已经通过检查其类是否匹配 /^${instance_class}::/ 来进行这种处理。 .我把它留给你作为练习。为每个对象创建一个新类并不便宜,而且会消耗内存。

这样做是有正当理由的,但它们是异常(exception)的。你真的应该怀疑你是否应该做这种 monkey patching .一般情况下, action at a distance应该避免。

你可以使用子类、委托(delegate)或角色来完成同样的事情吗?

已经存在 Perl OO 系统可以为您做这件事以及更多。你应该使用一个。 Moose , Moo (来自 Role::Tiny ) 和 Mouse都可以为实例添加角色。

关于perl - 在 perl 中向现有对象添加新方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28373405/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com