перегрузка объекта Perl для перенаправления хеш-доступа к пользовательской подпрограмме - PullRequest
3 голосов
/ 23 сентября 2019

Некоторое время назад я написал процедуру, которая анализирует данную строку и возвращает запись в виде хеша (field => value, field2 => value2).Отлично, за исключением того, что требования изменились, и теперь мне нужно вернуть больше данных и предложить методы получения, чтобы получить эти данные.Итак, я настроил подпрограмму так, чтобы она возвращала объект Record, который хранит этот же хэш в атрибуте data.

Однако это нарушит унаследованный код, который ожидает хеш, чтобы он мог получить данныеиспользуя $record->{field}.С новым объектом Record путь к этим данным теперь $record->{data}->{field} или $record->getByShortName('field').

Моя идея состояла в том, чтобы перегрузить метод FETCH объекта и вернуть соответствующее поле.Тем не менее, это не похоже на работу.Похоже, FETCH никогда не вызывается.

Я ищу три совета:

  1. Как правильно перегрузить мой объект, чтобы попытки доступа к хэшу были перенаправлены на пользовательскийметод объекта?
  2. Это рекомендуемый способ работы или будет существенное снижение скорости?
  3. Существуют ли лучшие методы для обеспечения обратной совместимости в моем случае?

Вот MVE:

Record.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
}

test.pl

use Record;

my $inst = Record->new();

print($inst->{answer}."\n");
print($inst->{question}."\n");

Ответы [ 2 ]

6 голосов
/ 23 сентября 2019

Record является благословенной ссылкой на хеш, поэтому если вы перегрузите оператор %{}, у вас будут проблемы с доступом к полям базового хеша.

Авторы overload подумали об этом, ипредоставил прагму overloading как способ отключить перегрузку для этого и некоторых других случаев использования.

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

До 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;
}
1 голос
/ 23 сентября 2019

Вам необязательно нужен специальный конструктор для объектов Perl.Вы можете определить свой Record класс, а затем просто return bless $hashref, 'Record';, где вы сейчас делаете return $hashref;.Весь код, который работает непосредственно с хеш-кодом, будет продолжать работать, но вы также сможете вызывать методы для него.

...