2010-02-24 20 views
39

De perldoc -f bless:¿Cómo puedo deshacer un objeto en Perl?

bless REF,CLASSNAME

Esta función cuenta la cosita que hace referencia REF que ahora
es un objeto en el paquete CLASSNAME.

¿Hay alguna forma de obtener una estructura no autorizada sin copia innecesaria?

+1

Ver también http://www.perlmonks.org/?node_id=183348 –

+0

@Ether: Por ejemplo, Template :: Toolkit. El operador punto ''.'' se usa para acceder a listas y hashes o para llamar a métodos de objetos. TT siempre intenta primero un método de objeto. –

+4

FWIW Necesito 'no disponible' porque' YAML :: Any :: Dump() 'conservará la naturaleza bendecida de un objeto, no quiero almacenar eso, pero a veces los hashes de datos que estoy descargando son bendecidos. También 'Moose-> new' es muy quisquilloso y no tomará un bendito hashref para una discusión. – Schwern

Respuesta

36

Data::Structure::Util

unbless($ref)

Retire la bendición de los objetos que se encuentran dentro de la estructura de datos pasado.

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

Salida:

My : 237356 
HASH : 237356
12

Acme::Curse :)

Actualización: Gracias, Ivan! Mezclé módulos. En realidad quería dar un enlace a Acme::Damn :))

P. S. Véase también Acme::Sneeze :)

P. P. S. no tiene ningún uso real, es por eso que es Acme::. Ver la publicación de Brian.

+1

Pero este módulo crea una copia del objeto. –

+6

Atribuido a Mike Andrews en alt.sysadmin.recovery: "Perl ya tiene _bless_, y sabemos lo que hace, ¿no? Perl también debería tener _smite_, y sabemos lo que debería hacer también. Si se hubieran implementado más idiomas, _smite_, los programadores restantes serían mejores que el promedio actual ". –

27

Data::Structure::Util tiene una función unbless que lo hará por usted. Como señala Erik, JSON::XS normalmente no aceptará referencias bendecidas (aunque desearía que simplemente lo ignore y trate con la estructura de datos). No hay forma de evitarlo en este caso.

Pero considere por qué cree que necesita deshacerlo. ¿Estás haciendo esto para una de tus clases o una clase diferente? Esto suena sospechosamente a The Wrong Thing To Do. Puede haber una mejor manera.

Tiene el mismo problema que romper la encapsulación porque tiene que asumir que sabe cuál es la estructura interna de la referencia. Si va a hacer eso, puede simplemente ignorar las cosas orientadas a objetos y acceder a la estructura directamente.

Si va a hacer esto para su propia clase, considere proporcionar un método para devolver una estructura de datos (que no tiene que ser la estructura original) en lugar de cambiar el objeto.

Mencione en un comentario de seguimiento que podría estar haciendo esto para evitar el comportamiento de algunos Toolkit de plantillas. Tuve esta situación de dos maneras dependiendo de la situación:

  • Solo pase los datos que necesita a la plantilla en lugar de todo el objeto.
  • Agregue métodos al objeto para obtener los datos que desea en la plantilla.

Perl es DWIM, pero TT es incluso DWIMmier, lo que a veces es desafortunado.


Aquí un corte rápido cuando defino un TO_JSON en UNIVERSAL por lo que se aplica a todos los objetos. Realiza una copia profunda, la deshace y devuelve la estructura de datos.

#!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 para llegar al problema real. – Ether

+2

no válido a menudo es útil, como cuando depura un estado interno y desea volcar un objeto bendecido en un ciclo cerrado ... con json :: xs porque Dumper es 100 veces más lento y json :: xs no se va a volcar un objeto bendito ... incluso si es solo un hashref. –

+1

De hecho, JSON :: XS es ​​el único lugar donde no he podido hacerlo de otra manera. Gracias, he actualizado mi respuesta. –

19

Si sabe de qué está respaldado su objeto, puede hacerlo sin usar paquetes.

Hash

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

matriz

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

Scalar

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

+1 porque esto resolvió exactamente mi problema, es decir, solo quería acceder "temporalmente" a la estructura de datos subyacente del objeto (un Hash) para volcarlo fácilmente con YAML :: Tiny. –

+2

Esto solo funciona si solo se bendice el nivel superior. Los valores de hash o elementos de matriz pueden ser referencias bendecidas. –

Cuestiones relacionadas