2010-02-24 13 views
39

Od perldoc -f bless:Jak mogę unbless obiektu w Perl?

bless REF,CLASSNAME

Funkcja ta opowiada thingy odwołuje REF że teraz
przedmiot w paczce CLASSNAME.

Czy istnieje sposób na uzyskanie niezabezpieczonej struktury bez niepotrzebnego kopiowania?

+1

Zobacz również http://www.perlmonks.org/?node_id=183348 –

+0

@Ether: Na przykład, Szablon :: Toolkit. Operator kropki ''.'' służy do uzyskiwania dostępu do list i skrótów lub do wywoływania metod obiektowych. TT zawsze próbuje najpierw metody obiektowej. –

+4

FWIW Potrzebuję 'unbless' ponieważ' YAML :: Any :: Dump() 'zachowa błogosławioną naturę obiektu, nie chcę tego przechować, ale czasami skróty danych, które zrzucam są błogosławione. Również "Łoś-> nowy" jest bardzo wybredny i nie bierze błogosławionego haszyszu do kłótni. – Schwern

Odpowiedz

36

Data::Structure::Util

unbless($ref)

Usuń błogosławieństwo od wszelkich przedmiotów znalezionych w przekazanym struktury danych.

#!/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; 

wyjściowa:

My : 237356 
HASH : 237356
12

Acme::Curse :)

Aktualizacja: Dziękuję, Ivan! Wymieszałem moduły. Właściwie chciałem dać link do Acme::Damn :))

P. S. Zobacz również Acme::Sneeze :)

P. P. S. To nie ma rzeczywistego wykorzystania, dlatego to Acme::. Zobacz post Briana.

+1

Ale ten moduł tworzy kopię obiektu. –

+6

Przypisany Mike'owi Andrewsowi w alt.sysadmin.recovery: "Perl już ma _bless_ i wiemy, co robi, tak? Perl powinien również mieć _smite_, i wiemy, co powinien on zrobić, gdyby więcej języków miało _smite_ implementowane, pozostali programiści byliby lepsi niż obecna średnia. " –

27

Data::Structure::Util ma unbless funkcję, która zrobi to za Ciebie. Jak wskazuje Erik, JSON::XS zwykle nie przyjmuje błogosławionych odniesień (chociaż żałuję, że po prostu nie zignoruje tego i nie zajmie się strukturą danych). W tym przypadku nie da się obejść.

Ale zastanów się, dlaczego uważasz, że nie powinieneś tego robić. Czy robisz to dla jednej z twoich własnych klas lub innej klasy? Brzmi to podejrzanie jak The Wrong Thing To Do. Może być lepszy sposób.

Masz ten sam problem co łamanie enkapsulacji, ponieważ musisz założyć, że wiesz, jaka jest wewnętrzna struktura odwołania. Jeśli zamierzasz to zrobić, możesz po prostu zignorować obiekty zorientowane obiektowo i uzyskać bezpośredni dostęp do struktury.

Jeśli zamierzasz to zrobić dla własnej klasy, rozważ dostarczenie metody zwracania struktury danych (która nie musi być oryginalną strukturą) zamiast zmiany obiektu.

Wspominasz w kolejnym komentarzu, że możesz to zrobić, aby obejść zachowanie szablonu Toolkit. Miałem tę sytuację na dwa sposoby w zależności od sytuacji:

  • Przekazuj tylko potrzebne dane do szablonu zamiast do całego obiektu.
  • Dodaj metody do obiektu, aby uzyskać żądane dane w szablonie.

Perl to DWIM, ale TT to nawet DWIMmier, co czasami jest niefortunne.


Oto szybki hack, gdzie mogę zdefiniować TO_JSON w UNIVERSAL więc ma ona zastosowanie do wszystkich obiektów. Tworzy głęboką kopię, unsorbuje ją i zwraca strukturę danych.

#!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); 
+2

+1 za uzyskanie prawdziwego problemu. – Ether

+2

unbless jest często pomocny, na przykład podczas debugowania stanu wewnętrznego i chcesz zrzucić błogosławiony obiekt w ciasnej pętli ... z json :: xs, ponieważ Dumper jest 100 razy wolniejszy, a json :: xs nie zrzuca błogosławiony przedmiot ... nawet jeśli to tylko hashref. –

+1

Rzeczywiście, JSON :: XS jest jedynym miejscem, w którym nie mogłem tego zrobić w żaden inny sposób. Dzięki, zaktualizowałem swoją odpowiedź. –

19

Jeśli wiesz, co obiekt jest wspierany, możesz to zrobić bez użycia pakietów.

Hash

$obj = bless {}, 'Obj'; 
print ref $obj, "\n"; 
$obj = { %$obj }; 
print ref $obj, "\n"; 

Array

$obj = bless [], 'Obj'; 
print ref $obj , "\n"; 
$obj = [ @$obj ]; 
print ref $obj, "\n"; 

Skalar

$obj = bless \$a, "Obj"; 
print ref $obj, "\n"; 
$obj = \${ $$obj }; 
print ref $obj, "\n"; 
+2

+1, ponieważ to właśnie rozwiązało mój problem, a mianowicie po prostu chciałem "tymczasowo" uzyskać dostęp do podstawowej struktury danych obiektu (Hash), aby łatwo zrzucić go za pomocą YAML :: Tiny. –

+2

Działa to tylko wtedy, gdy błogosławiony jest tylko najwyższy poziom. Wartości mieszania lub elementy tablicy mogą same być błogosławionymi odniesieniami. –

Powiązane problemy