重载Perl对象以将哈希访问重定向到自定义例程

blu*_*isk 3 perl overloading

前一段时间,我编写了一个例程,该例程解析给定的字符串并以hash的形式返回记录(field => value, field2 => value2)。很好,除了需求已更改,我现在需要返回更多数据并提供获取方法以获取此数据。因此,我调整了例程以返回一个Record对象,该对象将相同的哈希存储在data属性中。

但是,这将破坏期望散列的旧代码,以便可以使用来获取数据$record->{field}。对于新Record对象,此数据的路径现在为$record->{data}->{field}$record->getByShortName('field')

我的想法是重载对象的FETCH方法并返回相应的字段。但是,这似乎不起作用。似乎从未调用过FETCH。

我正在寻找三点建议:

  1. 如何正确重载我的对象,以便将哈希访问尝试重定向到该对象的自定义方法?
  2. 这是一种明智的工作方式,还是会造成巨大的速度损失?
  3. 在我的情况下,有没有更好的方法来保持向后兼容性?

这是一个MVE:

记录.pm

package Record;

use strict;
use warnings;
use Data::Dumper;
use overload fallback => 1, '%{}' => \&access_hash;

sub new {
    my ($class, %args) = @_;
    my %fields = (answer =>  42, question => 21);
    $args{fields} = \%fields;
    return bless { %args }, $class;
}

sub access_hash {
    my ($self) = shift;
    return $self;  # cannot return $self->{fields} because that would recurse ad infinitum
}

sub FETCH {
    print(Dumper(@_));  # does not return anything, is this method not being called
}
Run Code Online (Sandbox Code Playgroud)

test.pl

use Record;

my $inst = Record->new();

print($inst->{answer}."\n");
print($inst->{question}."\n");
Run Code Online (Sandbox Code Playgroud)

mob*_*mob 6

Record是受祝福的哈希引用,因此,如果您使%{}运算符超载,则将难以访问基础哈希的字段。

overload笔者想到这,并提供了overloading编译,以此来为这个禁止超载和其他一些使用情况。

use overload '%{}' => \&access_hash;
...
sub access_hash {
    no overloading '%{}';
    my ($self) = shift;
    return $self->{fields};
}
Run Code Online (Sandbox Code Playgroud)

在Perl 5.10之前,解决方法是通过暂时将对象重新赋予不会激活重载运算符的对象来禁用重载。

sub access_hash {
    my ($self) = shift;
    my $orig_ref = ref($self);
    bless $self, "#$%^&*()";
    my $fields = $self->{fields};
    bless $self, $orig_ref;
    return $fields;
}
Run Code Online (Sandbox Code Playgroud)