Как я могу unbless объект в Perl?

С perldoc -F и благословить:

bless REF,CLASSNAME

эта функция сообщает вещь, на которую ссылается REF что теперь
объект в CLASSNAME пакета.

есть ли способ получить незапятнанную структуру без ненужного копирования?

4 ответов


Данные::Структура:: Util

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;

выход:

My : 237356
HASH : 237356

Данные::Структура:: Util есть unbless функция, которая сделает это за вас. Как указывает Эрик,JSON:: XS обычно не принимает благословенные ссылки (хотя я хотел бы, чтобы он просто игнорировал это и занимался структурой данных). В этом случае ничего не поделаешь.

но подумайте, почему вы думаете, что вам нужно его разблокировать. Вы делаете это для одного из своих классов или для другого класса? Это подозрительно похоже на неправильный поступок. Возможно, есть лучший способ.

у вас та же проблема, что и нарушение инкапсуляции, потому что вы должны предположить, что знаете, какова внутренняя структура ссылки. Если вы собираетесь это сделать, вы можете просто игнорировать объектно-ориентированный материал и напрямую обращаться к структуре.

если вы собираетесь сделать это для своего собственного класса, рассмотрите возможность предоставления метода для возврата структуры данных (которая не должна быть исходной структурой) вместо изменения объект.

вы упоминаете в последующем комментарии, что вы можете сделать это, чтобы обойти некоторые шаблоны поведения инструментария. У меня была эта ситуация двумя способами в зависимости от ситуации:

  • передайте только необходимые вам данные в шаблон вместо всего объекта.
  • добавьте методы к объекту, чтобы получить данные, которые вы хотите в шаблоне.

Perl-DWIM, но TT еще DWIMmier, что к сожалению иногда.


вот быстрый взлом, где я определяю TO_JSON на UNIVERSAL так это относится ко всем объектам. Он делает глубокую копию, unblesses его и возвращает структуру данных.

#!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:: Curse :)

обновление: спасибо, Иван! Я перепутал модули. На самом деле я хотел дать ссылку на Acme:: Черт :))

П. С. см. также Acme:: Чихать :)

П. П. С. он не имеет реальной пользы, вот почему это Acme::. См. сообщение Брайана.