Как я могу разблокировать объект в Perl? - PullRequest
42 голосов
/ 24 февраля 2010

С perldoc -f благослови :

bless REF,CLASSNAME

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

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

Ответы [ 4 ]

39 голосов
/ 25 февраля 2010

Данные :: Структура :: 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
29 голосов
/ 25 февраля 2010

Data :: Structure :: Util имеет функцию 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 );
24 голосов
/ 01 сентября 2011

Если вы знаете, чем поддерживается ваш объект, вы можете сделать это без использования пакетов.

Hash

$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";
12 голосов
/ 24 февраля 2010

Acme :: Curse :)

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

P. S. См. Также Acme :: Sneeze :)

P. P. S. Это не имеет никакого реального использования, поэтому оно Acme::. Смотрите сообщение Брайана.

...