Как я могу разблокировать объект в Perl?
bless REF,CLASSNAME
Эта функция сообщает вещь, на которую ссылается
REF
что сейчас
объект вCLASSNAME
пакет.
Есть ли способ получить непослушную структуру без ненужного копирования?
4 ответа
unbless($ref)
Удалите благословение с любых объектов, найденных в переданной структуре данных.
#!/usr/bin/perl
use strict; use warnings;
use Scalar::Util qw( refaddr );
use Data::Structure::Util qw( unbless );
my $x = bless { a => 1, b => 2 } => 'My';
printf "%s : %s\n", ref $x, refaddr $x;
unbless $x;
printf "%s : %s\n", ref $x, refaddr $x;
Выход:
Мой: 237356 ХЭШ: 237356
Данные:: Структура:: Утиль имеет unbless
функция, которая сделает это за вас. Как указывает Эрик, JSON:: XS обычно не принимает благословенные ссылки (хотя я хотел бы, чтобы он просто игнорировал это и имел дело со структурой данных). Там нет никакого способа обойти это в этом случае.
Но подумайте, почему вы думаете, что вам нужно снять его. Вы делаете это для одного из ваших собственных классов или другого класса? Это звучит подозрительно, как The Wrong Thing To Do. Там может быть лучший способ.
У вас та же проблема, что и при нарушении инкапсуляции, поскольку вы должны предполагать, что знаете, какова внутренняя структура ссылки. Если вы собираетесь это сделать, вы можете просто проигнорировать объектно-ориентированные вещи и получить доступ к структуре напрямую.
Если вы собираетесь сделать это для своего собственного класса, рассмотрите возможность предоставления метода для возврата структуры данных (которая не должна быть исходной структурой) вместо изменения объекта.
В последующем комментарии вы упоминаете, что, возможно, делаете это, чтобы обойти поведение Template Toolkit. У меня была эта ситуация двумя способами в зависимости от ситуации:
- Передайте только необходимые данные в шаблон, а не весь объект.
- Добавьте методы к объекту, чтобы получить необходимые данные в шаблоне.
Perl - это DWIM, а TT - даже DWIMmier, что иногда бывает неудачно.
Вот быстрый взлом, где я определяю TO_JSON
в UNIVERSAL
так что это относится ко всем объектам. Он делает глубокую копию, разбирает ее и возвращает структуру данных.
#!perl
use v5.10;
sub UNIVERSAL::TO_JSON {
my( $self ) = shift;
use Storable qw(dclone);
use Data::Structure::Util qw(unbless);
my $clone = unbless( dclone( $self ) );
$clone;
}
my $data = bless {
foo => bless( [], 'Local::Array' ),
quack => bless( {
map { $_ => bless [$_, $_**2], 'Local::Array' }
grep { is_prime } 1 .. 10
}, 'Local::Hash' ),
}, 'Local::Hash';
use JSON::XS;
my $jsonner = JSON::XS->new->pretty->convert_blessed(1);
say $jsonner->encode( $data );
Если вы знаете, чем поддерживается ваш объект, вы можете сделать это без использования пакетов.
гашиш
$obj = bless {}, 'Obj';
print ref $obj, "\n";
$obj = { %$obj };
print ref $obj, "\n";
массив
$obj = bless [], 'Obj';
print ref $obj , "\n";
$obj = [ @$obj ];
print ref $obj, "\n";
скаляр
$obj = bless \$a, "Obj";
print ref $obj, "\n";
$obj = \${ $$obj };
print ref $obj, "\n";
Обновление: спасибо, Иван! Я перепутал модули. Вообще то я хотел дать ссылку на Acme:: Блин:))
PS Смотрите также Acme:: Sneeze:)
PPS Это не имеет никакого смысла, поэтому Acme::
, Смотрите пост Брайана.