Как я могу отменить благословение объекта в Perl?

StackOverflow https://stackoverflow.com/questions/2329385

  •  22-09-2019
  •  | 
  •  

Вопрос

От perldoc -f благословить:

bless REF,CLASSNAME

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

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

Это было полезно?

Решение

Данные::Структура::Утилита

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

Другие советы

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

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

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

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

В последующем комментарии вы упоминаете, что, возможно, делаете это, чтобы обойти некоторое поведение 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::.См. сообщение Брайана.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top